import { AgentTool } from './tool.js'; import { AgentInput, ExpectedIO, JSONSchema, LanguageModelSession, PromptMessage } from './types.js'; /** 실행 중 관찰할 수 있는 이벤트. 로깅/트레이싱 UI에 그대로 흘려주면 된다. */ export type AgentEvent = { type: 'tool-call'; agent: string; tool: string; args: unknown; } | { type: 'tool-result'; agent: string; tool: string; result: string; } | { type: 'tool-error'; agent: string; tool: string; error: string; } | { type: 'final'; agent: string; text: string; } | { type: 'context-overflow'; agent: string; }; export interface AgentOptions { /** 로그와 병렬 워크플로우 결과 라벨에 쓰인다. */ name?: string; /** 시스템 프롬프트. 이 에이전트의 역할을 여기 적는다. */ instruction?: string; /** 이 에이전트가 쓸 도구들. 하나라도 있으면 툴 루프 모드로 동작한다. */ tools?: Array; /** 0에 가까울수록 결정적. temperature와 topK는 같이 주는 것을 권장한다. */ temperature?: number; topK?: number; /** 툴 루프 최대 반복 횟수. 초과하면 에러를 던진다. */ maxSteps?: number; /** * true면 호출이 끝날 때마다 세션을 버린다. 즉 매 호출이 백지에서 시작한다. * * 워크플로우 단계로 쓰는 에이전트는 켜라. 안 켜면 flow.run()을 두 번째 호출할 때 * 첫 번째 실행의 대화가 컨텍스트에 그대로 남아 창을 갉아먹는다. * 반대로 챗봇처럼 대화를 이어가야 하면 꺼둔다(기본값). */ stateless?: boolean; /** * 도구 결과를 모델에게 돌려줄 때 잘라낼 최대 글자 수. 기본 4000자. * * 컨텍스트 창이 수천 토큰뿐이라, 큰 JSON을 그대로 넣으면 대화가 통째로 밀려난다. * 자르지 않으려면 Infinity를 준다. */ maxToolResultChars?: number; /** * 이전 대화 기록. agent.history를 저장해 뒀다가 그대로 넣으면 대화가 복원된다. * 새로고침 후 이어가기, 탭 간 동기화에 쓴다. */ history?: Array; /** * 오늘 날짜를 시스템 프롬프트에 한 줄로 넣는다. **기본값 false.** * * 온디바이스 모델은 학습 시점이 고정되어 있고 시계도 없어서, 날짜를 물으면 * 확신에 찬 오답을 낸다. 에러가 아니라 조용한 오답이라 가장 알아채기 어렵다. * 날짜나 기간을 다루는 에이전트라면 켜라. * * 도구로 만들지 않은 이유: 도구는 모델이 판단해 호출하고 결과를 되먹이는 왕복이 든다. * 날짜는 값이 정해져 있으므로 처음부터 넣는 편이 20토큰 남짓으로 훨씬 싸다. * * 사용자 기기의 로컬 날짜를 쓴다. 시각이 아니라 날짜만 넣는 이유는, * 세션이 몇십 분 살아 있으면 주입한 시각이 낡아버리기 때문이다. */ today?: boolean; /** 멀티모달을 쓸 때 선언한다. 예: [{ type: 'image' }] */ expectedInputs?: Array; expectedOutputs?: Array; /** 모델 다운로드 진행률(0~1) */ onDownloadProgress?: (loaded: number) => void; /** 전체 실행 취소용 */ signal?: AbortSignal; onEvent?: (event: AgentEvent) => void; } /** chain/parallel/router가 다루는 최소 단위. Agent도 워크플로우도 전부 이걸 만족한다. */ export interface Runnable { readonly name: string; run: (input: string) => Promise; } /** * Chrome Built-in AI 세션 하나를 감싼 에이전트. * * - 도구가 없으면 세션에 그대로 프롬프트를 넘긴다(스트리밍 가능). * - 도구가 있으면 제약 디코딩(JSON Schema)으로 툴 루프를 돌린다. * * 세션은 첫 호출 때 lazy 생성되므로 인스턴스를 미리 만들어 둬도 모델을 붙잡지 않는다. */ export declare class Agent implements Runnable { #private; readonly name: string; constructor(options?: AgentOptions); /** 세션을 만들고(이미 있으면 재사용) 반환한다. 동시 호출해도 한 번만 만든다. */ ready(): Promise; /** Runnable 구현. send()의 별칭이라 워크플로우에 그대로 꽂을 수 있다. */ run(input: string): Promise; /** * 지금까지의 대화 기록. JSON으로 저장했다가 history 옵션으로 넣으면 복원된다. * * ```ts * localStorage.setItem('chat', JSON.stringify(agent.history)) * const restored = new Agent({ instruction, history: JSON.parse(saved) }) * ``` */ get history(): Array; /** 한 번 질의하고 최종 텍스트를 받는다. 도구가 있으면 툴 루프를 끝까지 돌린다. */ send(input: AgentInput): Promise; /** * 토큰 단위 스트리밍. * 도구가 있는 에이전트는 루프가 끝나야 답이 확정되므로 최종 답변 한 덩어리만 흘린다. */ stream(input: AgentInput): AsyncGenerator; /** JSON Schema로 출력 형태를 강제해 객체로 받는다. 라우팅/평가에 쓴다. */ generate(input: AgentInput, schema: JSONSchema): Promise; /** 현재 대화를 복제한 새 에이전트. 같은 컨텍스트에서 갈라져 실험할 때 쓴다. */ fork(name?: string): Promise; /** * stateless 설정값. **지정하지 않았으면 undefined다**(false가 아니다). * * 워크플로우 조합기가 "정하지 않음"과 "일부러 끔"을 구분하는 데 쓴다. * 일부러 끈 것이라면 stateless: false를 명시해라. 그러면 경고가 나오지 않는다. */ get stateless(): boolean | undefined; /** 컨텍스트 사용량. 세션이 아직 없으면 null. */ get usage(): { used: number; total: number; } | null; /** 대화 기록까지 전부 버린다. 다음 호출은 백지에서 시작한다. */ reset(): void; /** 세션을 해제한다. 다 쓴 에이전트는 반드시 호출해 메모리를 돌려줘라. */ destroy(): void; } /** `new Agent(...)` 대신 쓰는 짧은 생성자 */ export declare function agent(options?: AgentOptions): Agent;