HarnessAgent
HarnessAgent
HarnessAgent 은 harness 어댑터가 뒷받침하는 AI SDK Agent 구현이에요. 미리 설정된 harness가 결과를 구동하는 동안 AI SDK 호환 결과를 반환하는 generate() 와 stream() 메서드를 제공해요.
출처: 문서
본문
설치 (Installation)
핵심 harness 패키지, harness 어댑터, sandbox 어댑터를 설치하세요:
Claude Code, Codex 같은 브리지 기반 harness는 @ai-sdk/sandbox-vercel 같은 실제 네트워크 sandbox가 필요해요. Pi 같은 호스트 런타임 harness는 sandbox에 노출된 포트가 필요 없으므로 @ai-sdk/sandbox-just-bash 로도 실행할 수 있어요.
에이전트 만들기 (Create an Agent)
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { claudeCode } from '@ai-sdk/harness-claude-code';
export const agent = new HarnessAgent({
harness: claudeCode,
model: 'claude-sonnet-4-6',
instructions:
'You are a careful coding assistant. Prefer small changes and explain tradeoffs.',
});
에이전트를 모듈 스코프에서 구성하세요. 이는 설정만 담고 라이브 세션은 아니에요. 라이브 상태는 HarnessAgentSession 에 속해요. sandbox 세션을 별도로 만들고 agent.createSession() 에 전달하세요:
import { createVercelNetworkSandboxSession } from '@ai-sdk/sandbox-vercel';
const sandboxSession = await createVercelNetworkSandboxSession({
runtime: 'node24',
ports: [4000],
template: await agent.getSandboxTemplate(),
});
model 을 설정해 harness 런타임이 사용할 모델을 선택하세요. 모델 식별자는 각 harness에 특화돼요. 생략하면 harness는 기본 모델을 사용해요. 모델은 턴마다 적용되므로 prepareCall 이 턴 사이에 교체할 수 있어요.
이 에이전트를 사용하려면 sandbox와 harness 자격 증명이 있는 환경 변수가 설정되어 있는지 확인하세요.
턴 실행하기 (Run a Turn)
const session = await agent.createSession({ sandboxSession });
let exitCode = 0;
try {
const result = await agent.generate({
session,
prompt: 'Create a short TODO.md for this repository.',
});
console.log(result.text);
} catch (err) {
exitCode = 1;
console.error(err);
} finally {
await session.destroy();
await sandboxSession.destroy();
process.exit(exitCode);
}
generate() 는 턴을 비우고 GenerateTextResult 를 반환해요.
점진적 출력에는 stream() 을 사용하세요:
const session = await agent.createSession({ sandboxSession });
let exitCode = 0;
try {
const result = await agent.stream({
session,
prompt: 'Create a short TODO.md for this repository.',
});
for await (const part of result.stream) {
if (part.type === 'text-delta') {
process.stdout.write(part.text);
}
}
} catch (err) {
exitCode = 1;
console.error(err);
} finally {
await session.destroy();
await sandboxSession.destroy();
process.exit(exitCode);
}
수명 주기 콜백 (Lifecycle Callbacks)
HarnessAgent 에 수명 주기 콜백을 설정해 에이전트 호출, 모델 단계, tool 실행을 관찰하세요:
const agent = new HarnessAgent({
harness: claudeCode,
tools: { weather },
onStart: event => console.log('call started', event.callId),
onStepStart: event => console.log('step started', event.stepNumber),
onLanguageModelCallStart: event =>
console.log('model call started', event.modelId),
onLanguageModelCallEnd: event =>
console.log('model call ended', event.finishReason),
onToolExecutionStart: event =>
console.log('tool started', event.toolCall.toolName),
onToolExecutionEnd: event => console.log('tool ended', event.toolOutput.type),
onStepEnd: step => console.log('step ended', step.stepNumber),
onEnd: event => console.log('call ended', event.finishReason),
});
개별 generate() 및 stream() 호출에 설정된 콜백은 설정 콜백에 더해 호출되며, 설정 콜백이 먼저 호출돼요. 콜백 오류는 무시되고 에이전트 실행을 바꾸지 않아요.
Harness 런타임은 내장 tools를 내부적으로 실행해요. 그런 tools의 경우 onToolExecutionStart 와 onToolExecutionEnd 는 런타임이 결과를 보고한 후의 논리적 tool 수명 주기를 설명해요. 콜백은 tool 결과가 결과 스트림에 게시되기 전에 여전히 전달돼요.
구조화된 출력 생성 (Generate Structured Output)
모든 턴에 동일한 타입화된 출력을 요구하려면 HarnessAgent 를 구성할 때 output 을 설정하세요. 에이전트는 출력 사양을 harness 어댑터용 JSON Schema로 변환하고, 완료된 응답을 검증하며, result.output 을 통해 파싱된 값을 반환해요.
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { Output } from 'ai';
import { z } from 'zod';
const agent = new HarnessAgent({
harness: claudeCode,
output: Output.object({
schema: z.object({
recipe: z.object({
name: z.string(),
ingredients: z.array(
z.object({
name: z.string(),
amount: z.number(),
unit: z.enum(['oz', 'fl oz', 'cup', 'gallon']),
}),
),
steps: z.array(z.string()),
}),
}),
}),
});
const session = await agent.createSession({ sandboxSession });
try {
const result = await agent.generate({
session,
prompt: 'Generate a lasagna recipe.',
});
console.dir(result.output, { depth: Infinity });
} finally {
await session.destroy();
}
stream() 으로는 partialOutputStream 을 읽어 점진적으로 파싱된 값을 얻고, result.output 을 await 해 검증된 최종 값을 얻으세요. 구조화된 데이터는 일반 텍스트 및 스트림 표면에도 JSON으로 남아 있어요. 어댑터는 finish 파트에 추가하지 않아요.
Harness 구조화된 출력은 스키마가 필요해요. 스키마 없는 Output.json() 과 스키마를 강제할 수 없는 어댑터 또는 런타임 설정은 HarnessCapabilityUnsupportedError 를 던져요. 어댑터 기능 표 참조.
메시지와 기록 (Messages and History)
harness 세션은 네이티브 대화 기록을 소유해요. messages 나 메시지 배열 prompt 를 전달하면 HarnessAgent 는 최신 사용자 메시지를 턴의 새 입력으로 삼아요. 전체 이전 대화를 harness로 재생하지 않아요.
끝에 있는 tool 메시지는 다르게 처리돼요. tool 승인 응답과 클라이언트 제공 tool 결과는 해당 요청이나 tool 호출을 만든 미완료 harness 턴을 계속해요.
이것은 일반적으로 애플리케이션이 전체 메시지 기록을 보내는 모델 호출과는 달라요. 채팅 라우트에서 메시지 재생에 의존하지 말고 harness 세션을 지속하고 재개하세요.
세션 수명 주기 (Session Lifecycle)
모든 세션을 명시적으로 종료하세요:
session.destroy()는 런타임을 중지하고 재개 가능성을 버려요.session.detach()는 런타임을 주차하고 재개 상태를 반환하며, 나중에 부착할 수 있도록 제공된 sandbox를 실행 상태로 남겨요. 턴이 미완료면 재개 상태에 연속 상태가 포함돼요.session.stop()은 재개 상태를 저장한 후 런타임을 중지해요. 턴이 미완료면 재개 상태에 연속 상태가 포함돼요.session.suspendTurn()은 프로세스 경계를 넘는 고급 활성 턴 연속용이에요.session.hasUnfinishedTurn()은 세션이 새 프롬프트를 받기 전에 현재 턴을 계속하거나 일시 중단해야 하는지 보고해요.
일회성 스크립트와 테스트에는 destroy() 를 사용하세요. 다중 턴 연속이 필요한 HTTP 라우트에는 detach() 또는 stop() 을 사용하세요.
턴 사이 설정 변경 (Change Settings Between Turns)
callOptionsSchema 와 prepareCall 을 사용해 각 새 턴에 대한 model, skills, instructions, tools 를 도출하세요. 이는 ToolLoopAgent 와 동일한 call-options 패턴을 따르는 것이에요:
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { tool } from 'ai';
import { z } from 'zod';
const getPolicy = tool({
description: 'Look up the active project policy.',
inputSchema: z.object({}),
execute: async () => 'Keep public APIs backward compatible.',
});
const agent = new HarnessAgent({
harness: claudeCode,
tools: { getPolicy },
callOptionsSchema: z.object({
area: z.enum(['frontend', 'backend']),
enablePolicyTool: z.boolean(),
useCheaperModel: z.boolean(),
}),
prepareCall: ({ options, ...call }) => ({
...call,
model: options.useCheaperModel ? 'claude-haiku-4-5' : undefined,
instructions: `Work as the ${options.area} specialist.`,
skills: [options.area === 'frontend' ? frontendSkill : backendSkill],
tools: options.enablePolicyTool ? { getPolicy } : undefined,
}),
});
const session = await agent.createSession({ sandboxSession });
try {
await agent.generate({
session,
prompt: 'Review the current implementation.',
options: {
area: 'frontend',
enablePolicyTool: false,
useCheaperModel: false,
},
});
await agent.generate({
session,
prompt: 'Now review the API contract.',
options: {
area: 'backend',
enablePolicyTool: true,
useCheaperModel: true,
},
});
} finally {
await session.destroy();
}
prepareCall 은 커스텀 options 가 검증된 후 새 프롬프트에 대해 실행돼요. 그 설정은 그 전체 턴 동안 고정돼요. 턴이 tool 결과, 승인, 중지 조건, 프로세스 핸드오프를 위해 일시 중지되면 연속은 동일한 설정을 재사용하고 prepareCall 을 다시 호출하지 않아요. 이는 설정이 턴 중간에 바뀌는 것을 방지해요.
model 을 바꿔도 새 harness 세션이 생기지 않아요. 각 어댑터는 세션의 대화 기록을 보존하면서 다음 프롬프트 전에 런타임을 전환/재구성해요.
Codex 어댑터는 codex exec resume 가 원래 네이티브 스레드 부트스트랩을 유지하므로 skills, instructions, tool 카탈로그가 바뀌면 새 네이티브 Codex 스레드를 시작해요. harness 세션은 사용 가능하지만 이전 네이티브 대화 컨텍스트는 그 설정 변경 경계를 넘어 이어지지 않아요. 설정이 변하지 않는 턴은 기존 네이티브 스레드를 계속해요.
abortSignal 을 generate() 또는 stream() 에 직접 전달하세요. 이미 호출별 설정이며 prepareCall 의 일부가 아니에요. output 은 응답 형식이 에이전트의 출력 스키마에 묶여 있으므로 에이전트에 고정돼 있어요.
agent.createSession() 에 sandboxSession 을 전달하면 호출자가 그 sandbox의 소유권을 유지해요. session.stop() 과 session.destroy() 는 여전히 harness 런타임을 종료하지만 제공된 sandbox 세션은 중지하거나 파괴하지 않아요. 이 경우 에이전트는 생성자에 sandbox 프로바이더가 필요 없어요.
const session = await agent.createSession({
sessionId: chatId,
sandboxSession,
});
try {
const result = await agent.stream({ session, messages });
for await (const part of result.stream) {
if (part.type === 'text-delta') {
process.stdout.write(part.text);
}
}
const resumeState = await session.detach();
await persistResumeState({ chatId, resumeState });
} catch (error) {
await session.destroy();
throw error;
}
재개하기 (Resuming)
불투명한 재개 상태를 지속하세요. 이 예제에서 harness sessionId 는 chatId 이고 sandbox ID는 동일한 알려진 ID에서 파생돼요. 애플리케이션이 sandbox ID를 파생할 수 없으면 sandboxSession.id 를 harness sessionId 및 재개 상태와 함께 지속하세요. 에이전트에 재개를 요청하기 전에 sandbox를 다시 부착하세요. 생성 시 sandboxId 를 선택하면 새 라이브 sandbox를 명명하고 조회하지 않아요. 명명된 sandbox가 존재하면 그 ID를 크리에이터와 재사용하면 실패하며, 조회는 재개 함수만 수행해요.
const resumeState = await loadResumeState({ chatId });
const sandboxId = `chat-${chatId}`;
const sandboxSession = resumeState
? await resumeVercelNetworkSandboxSession({ sandboxId })
: await createVercelNetworkSandboxSession({
sandboxId,
ports: [4000],
template: await agent.getSandboxTemplate(),
});
const session = await agent.createSession(
resumeState
? { sessionId: chatId, resumeFrom: resumeState, sandboxSession }
: { sessionId: chatId, sandboxSession },
);
HarnessAgent 는 런타임에 전달하기 전에 재개 상태가 같은 harness 어댑터에 의해 생성됐는지 검증해요. 재개 상태에 미완료 턴이 포함되면 새 프롬프트를 보내기 전에 continueStream() 또는 continueGenerate() 를 호출하세요. Vercel 재개 함수는 detach() 후에도 sandbox가 여전히 실행 중이거나 복원 가능한 스냅샷으로 중지됐는지 재부착해요. sandboxSession.destroy() 가 삭제한 후에는 그 ID를 재개할 수 없어요.
일시 중단된 턴 계속하기 (Continue a Suspended Turn)
프로세스 경계를 넘어 활성 턴을 넘겨야 하는 고급 워크플로의 경우 턴을 일시 중단하고 연속 상태를 지속하세요:
if (session.hasUnfinishedTurn()) {
const continuationState = await session.suspendTurn();
await persistContinuationState({ chatId, continuationState });
}
suspendTurn() 의 원시 연속 상태만 있을 때는 continueFrom 으로 재개한 다음 새 프롬프트 없이 턴을 계속하세요:
const session = await agent.createSession({
sessionId: chatId,
continueFrom: continuationState,
sandboxSession,
// Rebind this when the suspended turn used host-only tool context:
toolsContext,
});
const result = await agent.continueStream({ session });
점진적 출력에는 continueStream() 을, 연속된 턴을 비워 GenerateTextResult 를 반환하려면 continueGenerate() 를 사용하세요.
toolsContext 는 자격 증명이나 직렬화할 수 없는 호스트 객체를 포함할 수 있으므로 의도적으로 연속 상태에 저장되지 않아요. 일시 중단된 턴이 정적 또는 prepareCall 파생 tool 컨텍스트를 사용했다면 같은 tool별 맵을 createSession 에 전달해 턴을 계속하는 프로세스에서 다시 바인딩하세요.
Harness 단계 후 중지 (Stop After a Harness Step)
stopWhen 을 사용해 의미론적 단계 경계에 동의하세요. 술어는 또 다른 모델 단계로 계속될 수 있는 실제 harness tool 단계 후에 실행되며, 현재 호출의 완료된 단계를 받아요. 술어가 일치하면 반환된 결과가 끝나지만 기본 턴은 미완료 상태로 남아요. 터미널 텍스트 전용 단계는 대신 턴의 finish 이벤트를 소비하고 자연스럽게 끝나요.
import { isStepCount } from 'ai';
const steppedAgent = new HarnessAgent({
harness: claudeCode,
stopWhen: isStepCount(1),
});
const session = await steppedAgent.createSession({ sandboxSession });
const result = await steppedAgent.generate({
session,
prompt: 'Create a short TODO.md for this repository.',
});
if (session.hasUnfinishedTurn()) {
const continueFrom = await session.suspendTurn();
await persistContinuationState({ chatId, continuationState: continueFrom });
}
stopWhen 은 기본값이 없어요. 생략하면 HarnessAgent 는 턴이 자연스럽게 끝나거나 호스트 입력을 위해 일시 중지될 때까지 계속 실행돼요. 단계 제어가 없는 에이전트의 동작을 보존하죠. 술어 하나 또는 배열을 전달하고, 어떤 술어든 일치하면 현재 결과 조각을 끝내요. 중지된 턴은 createSession({ continueFrom }) 과 continueStream() 또는 continueGenerate() 로 재개하세요.
Sandbox 준비하기 (Prepare the Sandbox)
harness가 시작되기 전에 sandbox를 준비하려면 sandboxConfig 를 사용하세요.
sandboxConfig.onBootstrap 은 sandbox 템플릿 생성 중, harness 어댑터의 자체 부트스트랩 후, 스냅샷 가능한 프로바이더가 스냅샷을 게시하기 전에 실행돼요. 향후 세션이 재사용해야 하는 값비싼 설정에 사용하세요. onBootstrap 을 제공하면 bootstrapHash 도 제공하세요. 부트스트랩 출력이 재사용 가능한 스냅샷을 무효화해야 할 때마다 해시를 바꾸세요.
sandboxConfig.onSession 은 각 sandbox 세션이 획득되고 작업 디렉터리가 생긴 후(재개된 세션 포함) 실행돼요. 세션별 파일이나 가벼운 설정에 사용하세요.
const agent = new HarnessAgent({
harness: claudeCode,
sandboxConfig: {
workDir: 'repo',
bootstrapHash: 'ripgrep-v1',
onBootstrap: async ({ session, abortSignal }) => {
const result = await session.run({
command:
'command -v rg >/dev/null || (apt-get update && apt-get install -y ripgrep)',
abortSignal,
});
if (result.exitCode !== 0) {
throw new Error(`Failed to install ripgrep: ${result.stderr}`);
}
},
onSession: async ({ session, sessionWorkDir, abortSignal }) => {
await session.writeTextFile({
path: `${sessionWorkDir}/README.md`,
content: 'Session notes for the harness.',
abortSignal,
});
},
},
});
workDir 는 선택사항이에요. 제공하면 sandbox의 기본 작업 디렉터리에 상대적이어야 하며 세션 작업 디렉터리로 사용돼요. 생략하면 일반 세션은 기본 <harnessId>-<sessionId> 디렉터리를 사용하고, onBootstrap 은 sandbox의 기본 작업 디렉터리를 받아요.
재사용 가능한 Sandbox 준비 (Prepare Reusable Sandboxes)
sandbox를 만들기 전에 agent.getSandboxTemplate() 으로 하나의 harness의 부트스트랩 레시피와 sandboxConfig.onBootstrap 을 해석하세요. 템플릿의 정체성은 sandbox 생성 전에 알려져 있어요. Vercel은 준비된 스냅샷을 지속하고 그것으로 라이브 sandbox를 만듭니다. 동일한 호출은 스냅샷을 재사용해요:
const sandboxSession = await createVercelNetworkSandboxSession({
runtime: 'node24',
ports: [4000],
template: await agent.getSandboxTemplate(),
});
const session = await agent.createSession({ sandboxSession });
try {
await agent.generate({ session, prompt: 'Inspect this repository.' });
} finally {
await session.destroy();
await sandboxSession.destroy();
}
호출자 부트스트랩 훅을 공유하는 여러 harness의 경우 모든 어댑터에서 하나의 템플릿을 만드세요. 중복 harnessId 값에서는 마지막 어댑터가 승리하고, 레시피 정체성은 해싱 전에 정렬돼요. onSession 은 템플릿의 일부가 아니며 매 획득된 세션에서 별도로 실행돼요.
import { createHarnessSandboxTemplate } from '@ai-sdk/harness/agent';
const template = await createHarnessSandboxTemplate({
harnesses: [claudeCode, codex],
sandboxConfig,
});
console.log(template?.identity);
const sandboxSession = await createVercelNetworkSandboxSession({
source: { type: 'snapshot', snapshotId: baseSnapshotId },
ports: [4000],
template,
});
파생된 템플릿은 캐시 키에 소스 스냅샷 ID를 포함하므로, 같은 소스와 템플릿으로 반복 호출하면 준비된 스냅샷을 재사용해요. 캐시된 템플릿에 의존할 때 가변 Git 리비전, 이미지 태그, 소스 URL을 고정하세요. sandboxId 는 라이브 sandbox를 명명하며 재사용 가능한 템플릿을 명명하지 않아요. 기존 네이티브 name 옵션은 여전히 라이브 sandbox를 명명하며, 둘 다 제공되면 값이 일치해야 해요.
설정 (Settings)
HarnessAgent 는 다음 주요 설정을 받아요:
harness: 어댑터 인스턴스.model: 선택적 harness 특화 모델 식별자. 생략하면 harness는 기본 모델을 사용.id: 선택적 안정적인 에이전트 식별자.instructions: 지원되면 런타임의 시스템 또는 개발자 프롬프트에 추가되거나, 그렇지 않으면 사용자 프롬프트 앞에 추가되는 지시.headers: 모델 요청에 보내는 추가 헤더. 헤더는 생성 시 고정돼요.authorization,x-api-key,user-agent,x-client-app은 허용되지 않아요.callOptionsSchema와prepareCall: 커스텀 호출 옵션을 검증하고 각 새 턴에 model, skills, instructions, tools를 도출.output: 모든 턴에 적용되는 타입화된 출력 사양.stopWhen: 다른 모델 단계로 계속될 수 있는 완료된 harness tool 단계 후 결과 조각을 끝내는 조건.tools: harness가 호출할 때 호스트가 실행하는 AI SDK tools.activeTools: harness가 호출할 수 있는 내장 및 호스트 실행 tools의 허용 목록.inactiveTools: harness가 호출할 수 없는 내장 및 호스트 실행 tools의 거부 목록.skills: 어댑터가 표면화하는 지시 번들.permissionMode: 내장 tool 권한 모드.toolApproval: 호스트 실행 tools용 승인 상태 맵.sandboxConfig: sandbox 작업 디렉터리 및 수명 주기 훅 설정.telemetry,debug,onLog: 관측성 및 진단.
텔레메트리는 매 턴의 해결된 모델, 지시, 활성 호스트 정의 tools를 보고해요. Skills는 어댑터 컨텍스트이며 대응되는 AI SDK 텔레메트리 필드가 없으므로 표준 텔레메트리 이벤트에 포함되지 않아요.
어댑터 특화 설정은 어댑터 팩토리에 속해요. 예: createCodex({ reasoningEffort: 'high' }).
커스텀 Sandbox 오케스트레이션 (Custom Sandbox Orchestration)
애플리케이션이 sandbox를 직접 만들고 관리할 때는 먼저 네트워크 sandbox 세션을 준비한 다음 그 동일한 세션을 agent.createSession() 에 전달하세요. 에이전트는 sandbox를 만들지 않고 호출자 소유 sandbox를 중지하거나 파괴하지 않아요.
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { claudeCode } from '@ai-sdk/harness-claude-code';
import { createVercelNetworkSandboxSessionFromNativeSandbox } from '@ai-sdk/sandbox-vercel';
import { Sandbox } from '@vercel/sandbox';
const sandbox = await Sandbox.create({
runtime: 'node24',
ports: [4000],
});
const sandboxSession =
createVercelNetworkSandboxSessionFromNativeSandbox(sandbox);
const agent = new HarnessAgent({ harness: claudeCode });
const session = await agent.createSession({ sandboxSession });
try {
const result = await agent.stream({
session,
prompt: 'Create a short TODO.md for this repository.',
});
for await (const part of result.stream) {
if (part.type === 'text-delta') {
process.stdout.write(part.text);
}
}
} finally {
await session.destroy();
await sandboxSession.destroy();
}
네트워크 제어 없는 기본 Sandbox 세션 (Basic Sandbox Sessions Without Network Control)
다음 예제는 기본 세션 API가 어떻게 동작하는지 보여줘요. 프로젝트가 전체 네트워크 sandbox 세션을 노출할 수 있다면 그 세션을 전달하는 것을 강력히 권장해요. 프로젝트가 전체 네트워크 세션을 노출할 수 없을 때만 제한된 기본 세션을 전달하세요.
기본 sandbox 세션은 파일시스템과 프로세스 API만 노출해요. 에이전트는 여전히 sandbox 수명 주기를 호출자에게 맡겨요. 브리지 기반 harness의 경우 기본 세션이 해석할 수 없으므로 브리지 포트와 외부 도달 가능한 엔드포인트를 어댑터에 설정하세요.
import { HarnessAgent } from '@ai-sdk/harness/agent';
import { createClaudeCode } from '@ai-sdk/harness-claude-code';
import {
createVercelNetworkSandboxSessionFromNativeSandbox,
createVercelSandboxSessionFromNativeSandbox,
} from '@ai-sdk/sandbox-vercel';
import { Sandbox } from '@vercel/sandbox';
const sandbox = await Sandbox.create({
runtime: 'node24',
ports: [4000],
});
const sandboxSession =
createVercelNetworkSandboxSessionFromNativeSandbox(sandbox);
const portEndpoint = await sandboxSession.getPortEndpoint({
port: 4000,
protocol: 'ws',
});
const restrictedSandboxSession =
createVercelSandboxSessionFromNativeSandbox(sandbox);
const claudeCode = createClaudeCode({ port: 4000, portEndpoint });
const agent = new HarnessAgent({ harness: claudeCode });
const session = await agent.createSession({
sandboxSession: restrictedSandboxSession,
});
try {
const result = await agent.stream({
session,
prompt: 'Create a short TODO.md for this repository.',
});
for await (const part of result.stream) {
if (part.type === 'text-delta') {
process.stdout.write(part.text);
}
}
} finally {
await session.destroy();
await sandboxSession.destroy();
}
다음 단계 (Next Steps)
- 내장 및 호스트 실행 tools는 Tools
- 재사용 가능한 지시 번들은 Skills
- 어댑터 특화 설정은 Harness adapters
- 내구성 있는 장기 실행 턴은 Workflow utilities
useChat통합은 UI