@earendil-works/pi-agent-core 0.84.1 → 0.84.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/harness/events.d.ts +43 -0
- package/dist/harness/events.d.ts.map +1 -0
- package/dist/harness/events.js +65 -0
- package/dist/harness/events.js.map +1 -0
- package/dist/harness/session/jsonl/codec.d.ts +4 -2
- package/dist/harness/session/jsonl/codec.d.ts.map +1 -1
- package/dist/harness/session/jsonl/codec.js +127 -88
- package/dist/harness/session/jsonl/codec.js.map +1 -1
- package/dist/harness/session/jsonl/errors.d.ts +5 -1
- package/dist/harness/session/jsonl/errors.d.ts.map +1 -1
- package/dist/harness/session/jsonl/errors.js +10 -2
- package/dist/harness/session/jsonl/errors.js.map +1 -1
- package/dist/harness/session/jsonl/repo.d.ts +7 -3
- package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
- package/dist/harness/session/jsonl/repo.js +88 -45
- package/dist/harness/session/jsonl/repo.js.map +1 -1
- package/dist/harness/session/jsonl/storage.d.ts +1 -1
- package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
- package/dist/harness/session/jsonl/storage.js +28 -19
- package/dist/harness/session/jsonl/storage.js.map +1 -1
- package/dist/harness/session/jsonl/types.d.ts +1 -1
- package/dist/harness/session/jsonl/types.d.ts.map +1 -1
- package/dist/harness/session/jsonl/types.js.map +1 -1
- package/dist/harness/session/memory.d.ts +1 -1
- package/dist/harness/session/memory.d.ts.map +1 -1
- package/dist/harness/session/memory.js.map +1 -1
- package/dist/harness/session/session.d.ts +1 -1
- package/dist/harness/session/session.d.ts.map +1 -1
- package/dist/harness/session/session.js +7 -2
- package/dist/harness/session/session.js.map +1 -1
- package/dist/harness/session/state.d.ts +1 -1
- package/dist/harness/session/state.d.ts.map +1 -1
- package/dist/harness/session/state.js.map +1 -1
- package/dist/harness/session/testing/conformance.d.ts.map +1 -1
- package/dist/harness/session/testing/conformance.js +19 -0
- package/dist/harness/session/testing/conformance.js.map +1 -1
- package/dist/harness/session/types.d.ts +18 -5
- package/dist/harness/session/types.d.ts.map +1 -1
- package/dist/harness/session/types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +2 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +1 -0
- package/dist/proxy.js.map +1 -1
- package/dist/search/index.d.ts +21 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +2 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/scanning.d.ts +29 -0
- package/dist/search/scanning.d.ts.map +1 -0
- package/dist/search/scanning.js +103 -0
- package/dist/search/scanning.js.map +1 -0
- package/package.json +3 -3
- package/dist/harness/session/search.d.ts +0 -19
- package/dist/harness/session/search.d.ts.map +0 -1
- package/dist/harness/session/search.js +0 -42
- package/dist/harness/session/search.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/harness/session/types.ts"],"names":[],"mappings":"AACA,OAAO,gBAAgB,CAAC;AA0WxB,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC7B,IAAI,CAAmB;IAEhC,YAAY,IAAsB,EAAE,OAAe,EAAE,KAAa,EAAE;QACnE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CACjB;CACD","sourcesContent":["import type { StopReason, Usage } from \"@earendil-works/pi-ai\";\nimport \"../messages.ts\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport type { Session } from \"./session.ts\";\n\nexport type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\n\nexport type SessionStopReason = Exclude<StopReason, \"pending\"> | \"deferred\";\n\nexport interface IdGenerator {\n\tnext(): string;\n}\n\nexport interface EntryBase {\n\ttype: string;\n\tid: string;\n\tseq: number;\n\tparentId: string | null;\n\ttimestamp: number;\n}\n\nexport interface MessageEntry extends EntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n\tterminate?: true;\n}\n\nexport interface ModelChangeEntry extends EntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface ThinkingLevelEntry extends EntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ActiveToolsEntry extends EntryBase {\n\ttype: \"active_tools_change\";\n\tactiveToolNames: string[];\n}\n\nexport interface CompactionEntry extends EntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\tretainedTail: AgentMessage[];\n\ttokensBefore: number;\n\tdetails?: unknown;\n\tusage?: Usage;\n}\n\nexport interface BranchSummaryEntry extends EntryBase {\n\ttype: \"branch_summary\";\n\tfromId: string;\n\tsummary: string;\n\tdetails?: unknown;\n\tusage?: Usage;\n}\n\nexport interface CustomEntry extends EntryBase {\n\ttype: \"custom\";\n\tcustomType: string;\n\tdata?: unknown;\n}\n\nexport type Entry =\n\t| MessageEntry\n\t| ModelChangeEntry\n\t| ThinkingLevelEntry\n\t| ActiveToolsEntry\n\t| CompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry;\n\nexport type ProvisionedEntry<TEntry extends Entry = Entry> = TEntry extends Entry\n\t? Omit<TEntry, \"parentId\" | \"seq\" | \"timestamp\">\n\t: never;\n\nexport interface RecordBase {\n\tid: string;\n\tseq: number;\n\tlane: string;\n\ttimestamp: number;\n}\n\nexport interface OperationStartedRecord extends RecordBase {\n\ttype: \"operation_started\";\n\tsourceLeafId: string | null;\n\tintent:\n\t\t| {\n\t\t\t\tkind: \"run\";\n\t\t\t\t/** Normalized caller input before before_run; kept for suspended operations and before_resume. */\n\t\t\t\toriginalPrompt: AgentMessage[];\n\t\t\t\t/** Captured nextRun items, then the prompt, then before_run injections. */\n\t\t\t\tinitialMessages: ProvisionedEntry[];\n\t\t\t\tsystemPromptOverride?: string;\n\t\t\t\tresumeData?: { [extensionId: string]: JsonValue };\n\t\t }\n\t\t| {\n\t\t\t\tkind: \"compaction\";\n\t\t\t\tcustomInstructions?: string;\n\t\t\t\tresultEntryId: string;\n\t\t }\n\t\t| {\n\t\t\t\tkind: \"navigation\";\n\t\t\t\ttargetId: string | null;\n\t\t\t\tsummarize: boolean;\n\t\t\t\tcustomInstructions?: string;\n\t\t\t\tlabel?: string;\n\t\t\t\tsummaryEntryId?: string;\n\t\t };\n}\n\nexport interface AbortRequestedRecord extends RecordBase {\n\ttype: \"abort_requested\";\n\trunId: string;\n}\n\nexport interface OperationFinishedRecord extends RecordBase {\n\ttype: \"operation_finished\";\n\trunId: string;\n\toutcome: \"completed\" | \"aborted\" | \"failed\" | \"declined\";\n\terror?: { code: string; message: string };\n}\n\nexport type CompactionReason = \"manual\" | \"threshold\" | \"overflow\";\n\nexport type StepAttemptRecord = RecordBase &\n\t(\n\t\t| {\n\t\t\t\ttype: \"step_attempt\";\n\t\t\t\trunId: string;\n\t\t\t\tstep: \"assistant\" | \"branch_summary\";\n\t\t\t\tattempt: number;\n\t\t\t\tresultEntryId: string;\n\t\t\t\tcompactionReason?: never;\n\t\t }\n\t\t| {\n\t\t\t\ttype: \"step_attempt\";\n\t\t\t\trunId: string;\n\t\t\t\tstep: \"compaction\";\n\t\t\t\tattempt: number;\n\t\t\t\tresultEntryId: string;\n\t\t\t\t/** Persists why compaction summary generation started so recovery resumes the same work. */\n\t\t\t\tcompactionReason: CompactionReason;\n\t\t }\n\t);\n\nexport interface ToolStartedRecord extends RecordBase {\n\ttype: \"tool_started\";\n\trunId: string;\n\tassistantEntryId: string;\n\ttoolIndex: number;\n\ttoolCallId: string;\n\ttoolName: string;\n\teffectiveArgs: { [key: string]: unknown };\n\tresultEntryId: string;\n\treplay: \"never\" | \"safe\";\n}\n\nexport type QueueEnqueuedRecord = RecordBase &\n\t(\n\t\t| {\n\t\t\t\ttype: \"queue_enqueued\";\n\t\t\t\tqueue: \"steer\" | \"followUp\";\n\t\t\t\trunId: string;\n\t\t\t\ttarget: ProvisionedEntry;\n\t\t }\n\t\t| {\n\t\t\t\ttype: \"queue_enqueued\";\n\t\t\t\tqueue: \"nextRun\";\n\t\t\t\trunId?: never;\n\t\t\t\ttarget: ProvisionedEntry;\n\t\t }\n\t);\n\nexport interface QueueCancelledRecord extends RecordBase {\n\ttype: \"queue_cancelled\";\n\trunId?: string;\n\tentryId: string;\n}\n\nexport interface WriteDeferredRecord extends RecordBase {\n\ttype: \"write_deferred\";\n\trunId: string;\n\ttarget: ProvisionedEntry;\n}\n\nexport type UsageRecord = RecordBase & { type: \"usage\"; usage: Usage } & (\n\t\t| {\n\t\t\t\tcause: \"assistant\" | \"compaction\" | \"branch_summary\" | \"deferred_fetch\";\n\t\t\t\trunId: string;\n\t\t\t\tentryId: string;\n\t\t\t\tattempt: number;\n\t\t\t\tstopReason: SessionStopReason;\n\t\t }\n\t\t| { cause: \"tool\"; runId: string; entryId: string; toolCallId: string }\n\t\t| { cause: \"hook\"; runId: string; entryId: string }\n\t\t| { cause: \"adjustment\"; runId?: string; entryId?: string; details?: JsonValue }\n\t);\n\nexport type LaneRecord =\n\t| OperationStartedRecord\n\t| AbortRequestedRecord\n\t| OperationFinishedRecord\n\t| StepAttemptRecord\n\t| ToolStartedRecord\n\t| QueueEnqueuedRecord\n\t| QueueCancelledRecord\n\t| WriteDeferredRecord\n\t| UsageRecord;\nexport type NewRecord<TRecord extends LaneRecord = LaneRecord> = TRecord extends LaneRecord\n\t? Omit<TRecord, \"seq\" | \"timestamp\">\n\t: never;\n\nexport type EntryOrder = \"newestFirst\" | \"oldestFirst\";\n\nexport interface EntryCursor {\n\tafterSeq: number;\n}\n\nexport interface EntryQuery {\n\ttype?: Entry[\"type\"];\n\tcustomType?: string;\n\torder?: EntryOrder;\n\tlimit?: number;\n\tcursor?: EntryCursor;\n}\n\nexport interface BranchBounds {\n\tstart?: string;\n\tstopAtType?: Entry[\"type\"];\n\tstopAtId?: string;\n}\n\nexport interface RecordQuery {\n\tlane?: string;\n\ttype?: LaneRecord[\"type\"];\n\trunId?: string;\n\t/** Valid only with type \"operation_started\". */\n\toperationKind?: OperationStartedRecord[\"intent\"][\"kind\"];\n\tafterSeq?: number;\n\torder?: EntryOrder;\n\tlimit?: number;\n}\n\nexport interface SessionMetadata {\n\tid: string;\n\tcreatedAt: number;\n\tparentSessionId?: string;\n}\n\nexport interface SessionStats {\n\tmessageCount: number;\n\tcachedTokens: number;\n\tuncachedTokens: number;\n\ttotalTokens: number;\n\tcostTotal: number;\n}\n\nexport interface LanePointer {\n\tlane: string;\n\tleafId: string | null;\n}\n\nexport type LogItem =\n\t| { kind: \"entry\"; seq: number; entry: Entry }\n\t| { kind: \"record\"; seq: number; record: LaneRecord }\n\t| { kind: \"lane\"; seq: number; lane: string; leafId: string | null }\n\t| { kind: \"fact\"; seq: number; fact: \"name\"; name: string }\n\t| { kind: \"fact\"; seq: number; fact: \"label\"; targetId: string; label: string | undefined };\n\nexport interface LogOptions {\n\tafterSeq?: number;\n\tlimit?: number;\n}\n\nexport interface SessionStorage<TMetadata extends SessionMetadata = SessionMetadata> {\n\tgetMetadata(): Promise<TMetadata>;\n\n\t// Lanes\n\tgetLanes(): Promise<{ lane: string; leafId: string | null }[]>;\n\tcreateLane(lane: string, at: string | null): Promise<void>;\n\tmoveLane(lane: string, to: string | null): Promise<void>;\n\n\t// Entries and Records\n\tappendEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry>;\n\tappendRecord<TRecord extends LaneRecord>(record: NewRecord<TRecord>): Promise<TRecord>;\n\n\t// Reads\n\tgetEntry(id: string): Promise<Entry | undefined>;\n\tfindEntries(query?: EntryQuery): Promise<Entry[]>;\n\t/** start is mandatory here; defaulting to a lane's leaf is view sugar. */\n\tfindEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]>;\n\tfindRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tfindRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\t/**\n\t * Returns unfinished operation starts newest first. Recovery uses `limit: 2`:\n\t * zero results mean the lane is idle, one means it is suspended, and two\n\t * mean at least two operations are open, which is corruption. Further\n\t * results provide no additional recovery state.\n\t */\n\tfindOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]>;\n\tgetLog(options?: { afterSeq?: number; limit?: number }): Promise<LogItem[]>;\n\n\t// Global facts\n\tgetName(): Promise<string | undefined>;\n\tsetName(name: string): Promise<void>;\n\tgetLabel(id: string): Promise<string | undefined>;\n\tsetLabel(id: string, label: string | undefined): Promise<void>;\n\tgetStats(): Promise<SessionStats>;\n}\n\nexport interface SessionTree {\n\tgetLeafId(): Promise<string | null>;\n\tgetEntry(id: string): Promise<Entry | undefined>;\n\tgetStats(): Promise<SessionStats>;\n\tgetName(): Promise<string | undefined>;\n\tsetName(name: string): Promise<void>;\n\tgetLabel(targetId: string): Promise<string | undefined>;\n\tsetLabel(targetId: string, label: string | undefined): Promise<void>;\n\tfindEntries(query?: EntryQuery): Promise<Entry[]>;\n\tfindEntry(query?: EntryQuery): Promise<Entry | undefined>;\n\tfindEntriesOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry[]>;\n\tfindEntryOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry | undefined>;\n\tappendMessage(message: AgentMessage): Promise<string>;\n\tappendCustomEntry(customType: string, data?: unknown): Promise<string>;\n}\n\nexport interface SessionCreateOptions {\n\tid?: string;\n\tparentSessionId?: string;\n}\n\nexport type ForkOptions = { scope?: \"branch\"; entryId?: string; position?: \"before\" | \"at\" } | { scope: \"tree\" };\n\nexport interface SessionRepo<\n\tTMetadata extends SessionMetadata = SessionMetadata,\n\tTCreateOptions extends SessionCreateOptions = SessionCreateOptions,\n\tTListOptions = void,\n> {\n\tcreate(options: TCreateOptions): Promise<Session<TMetadata>>;\n\t/** Opens the session for writing and acquires any backend writer claim. */\n\topen(metadata: TMetadata): Promise<Session<TMetadata>>;\n\t/** Lists session metadata without opening sessions or acquiring writer claims. */\n\tlist(options?: TListOptions): Promise<TMetadata[]>;\n\tdelete(metadata: TMetadata): Promise<void>;\n\tfork(source: TMetadata, options: ForkOptions & TCreateOptions): Promise<Session<TMetadata>>;\n}\n\nexport type SessionErrorCode =\n\t| \"not_found\"\n\t| \"already_exists\"\n\t| \"invalid_entry\"\n\t| \"invalid_payload\"\n\t| \"invalid_lane\"\n\t| \"invalid_query\"\n\t| \"invalid_fork_target\"\n\t| \"storage\";\n\nexport class SessionError extends Error {\n\treadonly code: SessionErrorCode;\n\n\tconstructor(code: SessionErrorCode, message: string, cause?: Error) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"SessionError\";\n\t\tthis.code = code;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/harness/session/types.ts"],"names":[],"mappings":"AACA,OAAO,gBAAgB,CAAC;AA+XxB,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC7B,IAAI,CAAmB;IAEhC,YAAY,IAAsB,EAAE,OAAe,EAAE,KAAa,EAAE;QACnE,KAAK,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAAA,CACjB;CACD","sourcesContent":["import type { StopReason, Usage } from \"@earendil-works/pi-ai\";\nimport \"../messages.ts\";\nimport type { AgentMessage } from \"../../types.ts\";\nimport type { Session } from \"./session.ts\";\n\nexport type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };\n\nexport type SessionStopReason = Exclude<StopReason, \"pending\"> | \"deferred\";\n\nexport interface IdGenerator {\n\tnext(): string;\n}\n\nexport interface EntryBase {\n\ttype: string;\n\tid: string;\n\tseq: number; // shared sequence; read-side, storage-assigned\n\tparentId: string | null; // storage-assigned: the appending lane's leaf\n\ttimestamp: number; // Unix ms, storage-assigned\n}\n\nexport interface MessageEntry extends EntryBase {\n\ttype: \"message\";\n\tmessage: AgentMessage;\n\tterminate?: true;\n}\n\nexport interface ModelChangeEntry extends EntryBase {\n\ttype: \"model_change\";\n\tprovider: string;\n\tmodelId: string;\n}\n\nexport interface ThinkingLevelEntry extends EntryBase {\n\ttype: \"thinking_level_change\";\n\tthinkingLevel: string;\n}\n\nexport interface ActiveToolsEntry extends EntryBase {\n\ttype: \"active_tools_change\";\n\tactiveToolNames: string[];\n}\n\nexport interface CompactionEntry extends EntryBase {\n\ttype: \"compaction\";\n\tsummary: string;\n\tretainedTail: AgentMessage[];\n\ttokensBefore: number;\n\tdetails?: unknown;\n\tusage?: Usage;\n}\n\nexport interface BranchSummaryEntry extends EntryBase {\n\ttype: \"branch_summary\";\n\tfromId: string;\n\tsummary: string;\n\tdetails?: unknown;\n\tusage?: Usage;\n}\n\nexport interface CustomEntry extends EntryBase {\n\ttype: \"custom\";\n\tcustomType: string;\n\tdata?: unknown;\n}\n\nexport type Entry =\n\t| MessageEntry\n\t| ModelChangeEntry\n\t| ThinkingLevelEntry\n\t| ActiveToolsEntry\n\t| CompactionEntry\n\t| BranchSummaryEntry\n\t| CustomEntry;\n\nexport type ProvisionedEntry<TEntry extends Entry = Entry> = TEntry extends Entry\n\t? Omit<TEntry, \"parentId\" | \"seq\" | \"timestamp\">\n\t: never;\n\nexport interface RecordBase {\n\tid: string;\n\tseq: number;\n\tlane: string;\n\ttimestamp: number;\n}\n\nexport interface OperationStartedRecord extends RecordBase {\n\ttype: \"operation_started\";\n\tsourceLeafId: string | null;\n\tintent:\n\t\t| {\n\t\t\t\tkind: \"run\";\n\t\t\t\t/** Normalized caller input before before_run; kept for suspended operations and before_resume. */\n\t\t\t\toriginalPrompt: AgentMessage[];\n\t\t\t\t/** Captured nextRun items, then the prompt, then before_run injections. */\n\t\t\t\tinitialMessages: ProvisionedEntry[];\n\t\t\t\tsystemPromptOverride?: string;\n\t\t\t\tresumeData?: { [extensionId: string]: JsonValue };\n\t\t }\n\t\t| {\n\t\t\t\tkind: \"compaction\";\n\t\t\t\tcustomInstructions?: string;\n\t\t\t\tresultEntryId: string;\n\t\t }\n\t\t| {\n\t\t\t\tkind: \"navigation\";\n\t\t\t\ttargetId: string | null;\n\t\t\t\tsummarize: boolean;\n\t\t\t\tcustomInstructions?: string;\n\t\t\t\tlabel?: string;\n\t\t\t\tsummaryEntryId?: string;\n\t\t };\n}\n\nexport interface AbortRequestedRecord extends RecordBase {\n\ttype: \"abort_requested\";\n\trunId: string;\n}\n\nexport interface OperationFinishedRecord extends RecordBase {\n\ttype: \"operation_finished\";\n\trunId: string;\n\toutcome: \"completed\" | \"aborted\" | \"failed\" | \"declined\";\n\terror?: { code: string; message: string };\n}\n\nexport type CompactionReason = \"manual\" | \"threshold\" | \"overflow\";\n\nexport type StepAttemptRecord = RecordBase &\n\t(\n\t\t| {\n\t\t\t\ttype: \"step_attempt\";\n\t\t\t\trunId: string;\n\t\t\t\tstep: \"assistant\" | \"branch_summary\";\n\t\t\t\tattempt: number;\n\t\t\t\tresultEntryId: string;\n\t\t\t\tcompactionReason?: never;\n\t\t }\n\t\t| {\n\t\t\t\ttype: \"step_attempt\";\n\t\t\t\trunId: string;\n\t\t\t\tstep: \"compaction\";\n\t\t\t\tattempt: number;\n\t\t\t\tresultEntryId: string;\n\t\t\t\t/** Persists why compaction summary generation started so recovery resumes the same work. */\n\t\t\t\tcompactionReason: CompactionReason;\n\t\t }\n\t);\n\nexport interface ToolStartedRecord extends RecordBase {\n\ttype: \"tool_started\";\n\trunId: string;\n\tassistantEntryId: string;\n\ttoolIndex: number;\n\ttoolCallId: string;\n\ttoolName: string;\n\teffectiveArgs: { [key: string]: unknown };\n\tresultEntryId: string;\n\treplay: \"never\" | \"safe\";\n}\n\nexport type QueueEnqueuedRecord = RecordBase &\n\t(\n\t\t| {\n\t\t\t\ttype: \"queue_enqueued\";\n\t\t\t\tqueue: \"steer\" | \"followUp\";\n\t\t\t\trunId: string;\n\t\t\t\ttarget: ProvisionedEntry;\n\t\t }\n\t\t| {\n\t\t\t\ttype: \"queue_enqueued\";\n\t\t\t\tqueue: \"nextRun\";\n\t\t\t\trunId?: never;\n\t\t\t\ttarget: ProvisionedEntry;\n\t\t }\n\t);\n\nexport interface QueueCancelledRecord extends RecordBase {\n\ttype: \"queue_cancelled\";\n\trunId?: string;\n\tentryId: string;\n}\n\nexport interface WriteDeferredRecord extends RecordBase {\n\ttype: \"write_deferred\";\n\trunId: string;\n\ttarget: ProvisionedEntry;\n}\n\nexport type UsageRecord = RecordBase & { type: \"usage\"; usage: Usage } & (\n\t\t| {\n\t\t\t\tcause: \"assistant\" | \"compaction\" | \"branch_summary\" | \"deferred_fetch\";\n\t\t\t\trunId: string;\n\t\t\t\tentryId: string;\n\t\t\t\tattempt: number;\n\t\t\t\tstopReason: SessionStopReason;\n\t\t }\n\t\t| { cause: \"tool\"; runId: string; entryId: string; toolCallId: string }\n\t\t| { cause: \"hook\"; runId: string; entryId: string }\n\t\t| { cause: \"adjustment\"; runId?: string; entryId?: string; details?: JsonValue }\n\t);\n\nexport type LaneRecord =\n\t| OperationStartedRecord\n\t| AbortRequestedRecord\n\t| OperationFinishedRecord\n\t| StepAttemptRecord\n\t| ToolStartedRecord\n\t| QueueEnqueuedRecord\n\t| QueueCancelledRecord\n\t| WriteDeferredRecord\n\t| UsageRecord;\nexport type NewRecord<TRecord extends LaneRecord = LaneRecord> = TRecord extends LaneRecord\n\t? Omit<TRecord, \"seq\" | \"timestamp\">\n\t: never;\n\nexport type EntryOrder = \"newestFirst\" | \"oldestFirst\";\n\nexport interface EntryCursor {\n\tafterSeq: number;\n}\n\nexport interface EntryQuery {\n\ttype?: Entry[\"type\"];\n\tcustomType?: string; // for type \"custom\"\n\torder?: EntryOrder; // default newestFirst\n\tlimit?: number;\n\tcursor?: EntryCursor;\n}\n\n/** Bounds of a branch scan. Default: the whole path, leaf to root. */\nexport interface BranchBounds {\n\tstart?: string; // default: the view's lane leaf\n\tstopAtType?: Entry[\"type\"]; // scan ends after the first match, inclusive\n\tstopAtId?: string;\n}\n\nexport interface RecordQuery {\n\t/** Exact lane match. Omit to query every lane. */\n\tlane?: string;\n\t/** Exact record discriminant match. Omit to query every record type. */\n\ttype?: LaneRecord[\"type\"];\n\t/**\n\t * Operation identity. Matches OperationStartedRecord.id and the runId\n\t * property of operation-owned records. Records without an operation\n\t * identity do not match.\n\t */\n\trunId?: string;\n\t/** Exact operation intent kind. Valid only with type \"operation_started\". */\n\toperationKind?: OperationStartedRecord[\"intent\"][\"kind\"];\n\t/** Exclusive chronological lower bound: seq > afterSeq, regardless of order. */\n\tafterSeq?: number;\n\t/** Sequence order. Default: \"newestFirst\". */\n\torder?: EntryOrder;\n\t/** Positive maximum number of matching records. */\n\tlimit?: number;\n}\n\nexport interface SessionMetadata {\n\tid: string;\n\tcreatedAt: number;\n\tparentSessionId?: string;\n}\n\nexport interface SessionStats {\n\tmessageCount: number;\n\tcachedTokens: number;\n\tuncachedTokens: number;\n\ttotalTokens: number;\n\tcostTotal: number;\n}\n\nexport interface LanePointer {\n\tlane: string;\n\tleafId: string | null;\n}\n\nexport type LogItem =\n\t| { kind: \"entry\"; seq: number; entry: Entry }\n\t| { kind: \"record\"; seq: number; record: LaneRecord }\n\t| { kind: \"lane\"; seq: number; lane: string; leafId: string | null }\n\t| { kind: \"fact\"; seq: number; fact: \"name\"; name: string | undefined }\n\t| { kind: \"fact\"; seq: number; fact: \"label\"; targetId: string; label: string | undefined };\n\nexport interface LogOptions {\n\tafterSeq?: number;\n\tlimit?: number;\n}\n\nexport interface SessionStorage<TMetadata extends SessionMetadata = SessionMetadata> {\n\tgetMetadata(): Promise<TMetadata>;\n\n\t// Lanes\n\tgetLanes(): Promise<{ lane: string; leafId: string | null }[]>;\n\tcreateLane(lane: string, at: string | null): Promise<void>;\n\tmoveLane(lane: string, to: string | null): Promise<void>;\n\n\t// Entries and Records\n\tappendEntry<TEntry extends Entry>(entry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry>;\n\tappendRecord<TRecord extends LaneRecord>(record: NewRecord<TRecord>): Promise<TRecord>;\n\n\t// Reads\n\tgetEntry(id: string): Promise<Entry | undefined>;\n\tfindEntries(query?: EntryQuery): Promise<Entry[]>;\n\t/** start is mandatory here (as opposed to SessionTree's findEntriesOnBranch); defaulting to a lane's leaf is view sugar. */\n\tfindEntriesOnBranch(query: EntryQuery & BranchBounds & { start: string }): Promise<Entry[]>;\n\tfindRecords<K extends LaneRecord[\"type\"]>(\n\t\tquery: RecordQuery & { type: K },\n\t): Promise<Extract<LaneRecord, { type: K }>[]>;\n\tfindRecords(query?: RecordQuery): Promise<LaneRecord[]>;\n\t/**\n\t * Returns unfinished operation starts newest first. Recovery uses `limit: 2`:\n\t * zero results mean the lane is idle, one means it is suspended, and two\n\t * mean at least two operations are open, which is corruption. Further\n\t * results provide no additional recovery state.\n\t */\n\tfindOpenOperations(lane: string, options?: { limit?: number }): Promise<OperationStartedRecord[]>;\n\tgetLog(options?: { afterSeq?: number; limit?: number }): Promise<LogItem[]>;\n\n\t// Global facts\n\tgetName(): Promise<string | undefined>;\n\tsetName(name: string | undefined): Promise<void>;\n\tgetLabel(id: string): Promise<string | undefined>;\n\tsetLabel(id: string, label: string | undefined): Promise<void>;\n\tgetStats(): Promise<SessionStats>;\n}\n\nexport interface SessionTree {\n\tgetLeafId(): Promise<string | null>;\n\tgetEntry(id: string): Promise<Entry | undefined>;\n\tgetStats(): Promise<SessionStats>;\n\n\t// Global facts. Latest wins; not branch-scoped. \"set\", not \"append\":\n\t// append vocabulary is reserved for tree writes.\n\tgetName(): Promise<string | undefined>;\n\tsetName(name: string | undefined): Promise<void>;\n\tgetLabel(targetId: string): Promise<string | undefined>;\n\tsetLabel(targetId: string, label: string | undefined): Promise<void>;\n\n\t/** Session-wide, all branches, sequence order. */\n\tfindEntries(query?: EntryQuery): Promise<Entry[]>;\n\tfindEntry(query?: EntryQuery): Promise<Entry | undefined>;\n\n\t/** Branch-scoped: the path from start toward root. */\n\tfindEntriesOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry[]>;\n\tfindEntryOnBranch(query?: EntryQuery & BranchBounds): Promise<Entry | undefined>;\n\n\t// Writes. Resolve on durable acceptance; the returned id is the entry's\n\t// id (provisioned when the write defers).\n\tappendMessage(message: AgentMessage): Promise<string>;\n\tappendCustomEntry(customType: string, data?: unknown): Promise<string>;\n}\n\nexport interface SessionCreateOptions {\n\tid?: string;\n\tparentSessionId?: string;\n}\n\nexport type ForkOptions = { scope?: \"branch\"; entryId?: string; position?: \"before\" | \"at\" } | { scope: \"tree\" };\n\nexport interface SessionRepo<\n\tTMetadata extends SessionMetadata = SessionMetadata,\n\tTCreateOptions extends SessionCreateOptions = SessionCreateOptions,\n\tTListOptions = void,\n> {\n\tcreate(options: TCreateOptions): Promise<Session<TMetadata>>;\n\t/** Opens the session for writing and acquires any backend writer claim. */\n\topen(metadata: TMetadata): Promise<Session<TMetadata>>;\n\t/** Lists session metadata without opening sessions or acquiring writer claims. */\n\tlist(options?: TListOptions): Promise<TMetadata[]>;\n\tdelete(metadata: TMetadata): Promise<void>;\n\tfork(source: TMetadata, options: ForkOptions & TCreateOptions): Promise<Session<TMetadata>>;\n}\n\nexport type SessionErrorCode =\n\t| \"not_found\"\n\t| \"already_exists\"\n\t| \"invalid_entry\"\n\t| \"invalid_payload\"\n\t| \"invalid_lane\"\n\t| \"invalid_query\"\n\t| \"invalid_fork_target\"\n\t| \"storage\";\n\nexport class SessionError extends Error {\n\treadonly code: SessionErrorCode;\n\n\tconstructor(code: SessionErrorCode, message: string, cause?: Error) {\n\t\tsuper(message, cause === undefined ? undefined : { cause });\n\t\tthis.name = \"SessionError\";\n\t\tthis.code = code;\n\t}\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,6 @@ export * from "./harness/messages.ts";
|
|
|
10
10
|
export * from "./harness/prompt-templates.ts";
|
|
11
11
|
export * from "./harness/result.ts";
|
|
12
12
|
export * from "./harness/session/index.ts";
|
|
13
|
-
export * from "./harness/session/search.ts";
|
|
14
13
|
export * from "./harness/skills.ts";
|
|
15
14
|
export * from "./harness/system-prompt.ts";
|
|
16
15
|
export type { AiSpan, AiSpanAttributes, AiSpanEndAttributes, AiSpanEventAttributes, AiSpanEventName, AiSpanName, AiSpanStartAttributes, AiTelemetrySpan, HarnessSpan, HarnessSpanAttributes, HarnessSpanEndAttributes, HarnessSpanEventAttributes, HarnessSpanEventName, HarnessSpanName, HarnessSpanStartAttributes, HarnessTelemetrySpan, } from "./harness/telemetry.ts";
|
|
@@ -20,6 +19,7 @@ export { type AgentHarnessResources, type AgentHarnessStreamOptions, type AgentH
|
|
|
20
19
|
export * from "./harness/utils/shell-output.ts";
|
|
21
20
|
export * from "./harness/utils/truncate.ts";
|
|
22
21
|
export * from "./proxy.ts";
|
|
22
|
+
export * from "./search/index.ts";
|
|
23
23
|
export { setDefaultStreamFn } from "./stream-fn.ts";
|
|
24
24
|
export * from "./types.ts";
|
|
25
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,YAAY,EACX,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACvB,kCAAkC,EAClC,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,cAAc,IAAI,uBAAuB,EACzC,WAAW,EACX,UAAU,EACV,4BAA4B,EAC5B,0BAA0B,EAC1B,sBAAsB,EACtB,gBAAgB,EAChB,iCAAiC,EACjC,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,gCAAgC,EAChC,kCAAkC,EAClC,4BAA4B,EAC5B,uBAAuB,EACvB,kCAAkC,EAClC,wBAAwB,EACxB,aAAa,EACb,uBAAuB,EACvB,iCAAiC,EACjC,gBAAgB,GAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACN,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,GACtB,MAAM,8BAA8B,CAAC;AACtC,cAAc,YAAY,CAAC;AAE3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EACN,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,8BAA8B,EAC9B,KAAK,cAAc,EACnB,KAAK,4BAA4B,EACjC,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACN,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAE9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core Agent\n\nexport { uuidv7 } from \"@earendil-works/pi-ai\";\nexport type {\n\tAttributeValue,\n\tExactTelemetryAttributes,\n\tInferEventAttributes,\n\tInferOptionalAttributes,\n\tInferRequiredAndOptionalAttributes,\n\tInferStartAttributes,\n\tRecordedTelemetryEvent,\n\tRecordedTelemetrySpan,\n\tSchemaTelemetrySpan,\n\tSpanAttributes,\n\tSpanAttributes as TelemetrySpanAttributes,\n\tSpanOptions,\n\tSpanStatus,\n\tTelemetryAttributeDefinition,\n\tTelemetryAttributeMetadata,\n\tTelemetryAttributeType,\n\tTelemetryContext,\n\tTelemetryEventAttributeDefinition,\n\tTelemetryEventDefinition,\n\tTelemetryParentDefinition,\n\tTelemetrySchemaDefinition,\n\tTelemetrySchemaSpanEndAttributes,\n\tTelemetrySchemaSpanEventAttributes,\n\tTelemetrySchemaSpanEventName,\n\tTelemetrySchemaSpanName,\n\tTelemetrySchemaSpanStartAttributes,\n\tTelemetrySchemaSpanUnion,\n\tTelemetrySpan,\n\tTelemetrySpanDefinition,\n\tTelemetryStartAttributeDefinition,\n\tTypedSpanStarter,\n} from \"@earendil-works/pi-telemetry\";\nexport {\n\tcreateTypedSpanStarter,\n\tdefineTelemetrySchema,\n\tInMemoryTelemetryContext,\n\tNOOP_TELEMETRY_CONTEXT,\n} from \"@earendil-works/pi-telemetry\";\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\nexport * from \"./harness/agent-harness.ts\";\nexport {\n\ttype BranchPreparation,\n\ttype BranchSummaryDetails,\n\ttype BranchSummaryResult,\n\ttype CollectEntriesResult,\n\tcollectEntriesForBranchSummary,\n\ttype FileOperations,\n\ttype GenerateBranchSummaryOptions,\n\tgenerateBranchSummary,\n\tprepareBranchEntries,\n} from \"./harness/compaction/branch-summarization.ts\";\nexport {\n\ttype CompactionPreparation,\n\ttype CompactionSettings,\n\ttype CompactResult,\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgenerateSummaryWithUsage,\n\tgetLastAssistantUsage,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./harness/compaction/compaction.ts\";\nexport * from \"./harness/messages.ts\";\nexport * from \"./harness/prompt-templates.ts\";\n// Harness\nexport * from \"./harness/result.ts\";\nexport * from \"./harness/session/index.ts\";\nexport * from \"./harness/skills.ts\";\nexport * from \"./harness/system-prompt.ts\";\nexport type {\n\tAiSpan,\n\tAiSpanAttributes,\n\tAiSpanEndAttributes,\n\tAiSpanEventAttributes,\n\tAiSpanEventName,\n\tAiSpanName,\n\tAiSpanStartAttributes,\n\tAiTelemetrySpan,\n\tHarnessSpan,\n\tHarnessSpanAttributes,\n\tHarnessSpanEndAttributes,\n\tHarnessSpanEventAttributes,\n\tHarnessSpanEventName,\n\tHarnessSpanName,\n\tHarnessSpanStartAttributes,\n\tHarnessTelemetrySpan,\n} from \"./harness/telemetry.ts\";\nexport {\n\tAGENT_TELEMETRY_SCHEMAS,\n\tAI_TELEMETRY_SCHEMA,\n\tHARNESS_TELEMETRY_SCHEMA,\n\tstartAiSpan,\n\tstartHarnessSpan,\n} from \"./harness/telemetry.ts\";\nexport * from \"./harness/tools/index.ts\";\nexport {\n\ttype AgentHarnessResources,\n\ttype AgentHarnessStreamOptions,\n\ttype AgentHarnessStreamOptionsPatch,\n\ttype AgentHarnessTool,\n\ttype AgentHarnessToolContextSource,\n\tBranchSummaryError,\n\ttype BranchSummaryErrorCode,\n\tCompactionError,\n\ttype CompactionErrorCode,\n\ttype ExecutionEnv,\n\tExecutionError,\n\ttype ExecutionErrorCode,\n\terr,\n\tFileError,\n\ttype FileErrorCode,\n\ttype FileInfo,\n\ttype FileKind,\n\ttype FileSystem,\n\tgetOrThrow,\n\tgetOrUndefined,\n\tok,\n\ttype PromptTemplate,\n\ttype Shell,\n\ttype ShellExecOptions,\n\ttype Skill,\n\ttoError,\n} from \"./harness/types.ts\";\nexport * from \"./harness/utils/shell-output.ts\";\nexport * from \"./harness/utils/truncate.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\nexport * from \"./search/index.ts\";\n// Stream defaults\nexport { setDefaultStreamFn } from \"./stream-fn.ts\";\n// Types\nexport * from \"./types.ts\";\n"]}
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,6 @@ export * from "./harness/prompt-templates.js";
|
|
|
12
12
|
// Harness
|
|
13
13
|
export * from "./harness/result.js";
|
|
14
14
|
export * from "./harness/session/index.js";
|
|
15
|
-
export * from "./harness/session/search.js";
|
|
16
15
|
export * from "./harness/skills.js";
|
|
17
16
|
export * from "./harness/system-prompt.js";
|
|
18
17
|
export { AGENT_TELEMETRY_SCHEMAS, AI_TELEMETRY_SCHEMA, HARNESS_TELEMETRY_SCHEMA, startAiSpan, startHarnessSpan, } from "./harness/telemetry.js";
|
|
@@ -22,6 +21,7 @@ export * from "./harness/utils/shell-output.js";
|
|
|
22
21
|
export * from "./harness/utils/truncate.js";
|
|
23
22
|
// Proxy utilities
|
|
24
23
|
export * from "./proxy.js";
|
|
24
|
+
export * from "./search/index.js";
|
|
25
25
|
// Stream defaults
|
|
26
26
|
export { setDefaultStreamFn } from "./stream-fn.js";
|
|
27
27
|
// Types
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAkC/C,OAAO,EACN,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,GACtB,MAAM,8BAA8B,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,iBAAiB;AACjB,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAKN,8BAA8B,EAG9B,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAIN,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,UAAU;AACV,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAkC/C,OAAO,EACN,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,sBAAsB,GACtB,MAAM,8BAA8B,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,iBAAiB;AACjB,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAKN,8BAA8B,EAG9B,qBAAqB,EACrB,oBAAoB,GACpB,MAAM,8CAA8C,CAAC;AACtD,OAAO,EAIN,sBAAsB,EACtB,OAAO,EACP,2BAA2B,EAC3B,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,GACb,MAAM,oCAAoC,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,UAAU;AACV,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAmB3C,OAAO,EACN,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,WAAW,EACX,gBAAgB,GAChB,MAAM,wBAAwB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,OAAO,EAMN,kBAAkB,EAElB,eAAe,EAGf,cAAc,EAEd,GAAG,EACH,SAAS,EAKT,UAAU,EACV,cAAc,EACd,EAAE,EAKF,OAAO,GACP,MAAM,oBAAoB,CAAC;AAC5B,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,kBAAkB;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,QAAQ;AACR,cAAc,YAAY,CAAC","sourcesContent":["// Core Agent\n\nexport { uuidv7 } from \"@earendil-works/pi-ai\";\nexport type {\n\tAttributeValue,\n\tExactTelemetryAttributes,\n\tInferEventAttributes,\n\tInferOptionalAttributes,\n\tInferRequiredAndOptionalAttributes,\n\tInferStartAttributes,\n\tRecordedTelemetryEvent,\n\tRecordedTelemetrySpan,\n\tSchemaTelemetrySpan,\n\tSpanAttributes,\n\tSpanAttributes as TelemetrySpanAttributes,\n\tSpanOptions,\n\tSpanStatus,\n\tTelemetryAttributeDefinition,\n\tTelemetryAttributeMetadata,\n\tTelemetryAttributeType,\n\tTelemetryContext,\n\tTelemetryEventAttributeDefinition,\n\tTelemetryEventDefinition,\n\tTelemetryParentDefinition,\n\tTelemetrySchemaDefinition,\n\tTelemetrySchemaSpanEndAttributes,\n\tTelemetrySchemaSpanEventAttributes,\n\tTelemetrySchemaSpanEventName,\n\tTelemetrySchemaSpanName,\n\tTelemetrySchemaSpanStartAttributes,\n\tTelemetrySchemaSpanUnion,\n\tTelemetrySpan,\n\tTelemetrySpanDefinition,\n\tTelemetryStartAttributeDefinition,\n\tTypedSpanStarter,\n} from \"@earendil-works/pi-telemetry\";\nexport {\n\tcreateTypedSpanStarter,\n\tdefineTelemetrySchema,\n\tInMemoryTelemetryContext,\n\tNOOP_TELEMETRY_CONTEXT,\n} from \"@earendil-works/pi-telemetry\";\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\nexport * from \"./harness/agent-harness.ts\";\nexport {\n\ttype BranchPreparation,\n\ttype BranchSummaryDetails,\n\ttype BranchSummaryResult,\n\ttype CollectEntriesResult,\n\tcollectEntriesForBranchSummary,\n\ttype FileOperations,\n\ttype GenerateBranchSummaryOptions,\n\tgenerateBranchSummary,\n\tprepareBranchEntries,\n} from \"./harness/compaction/branch-summarization.ts\";\nexport {\n\ttype CompactionPreparation,\n\ttype CompactionSettings,\n\ttype CompactResult,\n\tcalculateContextTokens,\n\tcompact,\n\tDEFAULT_COMPACTION_SETTINGS,\n\testimateContextTokens,\n\testimateTokens,\n\tfindCutPoint,\n\tfindTurnStartIndex,\n\tgenerateSummary,\n\tgenerateSummaryWithUsage,\n\tgetLastAssistantUsage,\n\tprepareCompaction,\n\tserializeConversation,\n\tshouldCompact,\n} from \"./harness/compaction/compaction.ts\";\nexport * from \"./harness/messages.ts\";\nexport * from \"./harness/prompt-templates.ts\";\n// Harness\nexport * from \"./harness/result.ts\";\nexport * from \"./harness/session/index.ts\";\nexport * from \"./harness/skills.ts\";\nexport * from \"./harness/system-prompt.ts\";\nexport type {\n\tAiSpan,\n\tAiSpanAttributes,\n\tAiSpanEndAttributes,\n\tAiSpanEventAttributes,\n\tAiSpanEventName,\n\tAiSpanName,\n\tAiSpanStartAttributes,\n\tAiTelemetrySpan,\n\tHarnessSpan,\n\tHarnessSpanAttributes,\n\tHarnessSpanEndAttributes,\n\tHarnessSpanEventAttributes,\n\tHarnessSpanEventName,\n\tHarnessSpanName,\n\tHarnessSpanStartAttributes,\n\tHarnessTelemetrySpan,\n} from \"./harness/telemetry.ts\";\nexport {\n\tAGENT_TELEMETRY_SCHEMAS,\n\tAI_TELEMETRY_SCHEMA,\n\tHARNESS_TELEMETRY_SCHEMA,\n\tstartAiSpan,\n\tstartHarnessSpan,\n} from \"./harness/telemetry.ts\";\nexport * from \"./harness/tools/index.ts\";\nexport {\n\ttype AgentHarnessResources,\n\ttype AgentHarnessStreamOptions,\n\ttype AgentHarnessStreamOptionsPatch,\n\ttype AgentHarnessTool,\n\ttype AgentHarnessToolContextSource,\n\tBranchSummaryError,\n\ttype BranchSummaryErrorCode,\n\tCompactionError,\n\ttype CompactionErrorCode,\n\ttype ExecutionEnv,\n\tExecutionError,\n\ttype ExecutionErrorCode,\n\terr,\n\tFileError,\n\ttype FileErrorCode,\n\ttype FileInfo,\n\ttype FileKind,\n\ttype FileSystem,\n\tgetOrThrow,\n\tgetOrUndefined,\n\tok,\n\ttype PromptTemplate,\n\ttype Shell,\n\ttype ShellExecOptions,\n\ttype Skill,\n\ttoError,\n} from \"./harness/types.ts\";\nexport * from \"./harness/utils/shell-output.ts\";\nexport * from \"./harness/utils/truncate.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\nexport * from \"./search/index.ts\";\n// Stream defaults\nexport { setDefaultStreamFn } from \"./stream-fn.ts\";\n// Types\nexport * from \"./types.ts\";\n"]}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Proxy stream function for apps that route LLM calls through a server.
|
|
3
3
|
* The server manages auth and proxies requests to LLM providers.
|
|
4
4
|
*/
|
|
5
|
-
import { type AssistantMessage, type AssistantMessageEvent, type Context, EventStream, type Model, type SimpleStreamOptions, type StopReason } from "@earendil-works/pi-ai";
|
|
5
|
+
import { type AssistantMessage, type AssistantMessageEvent, type Context, EventStream, type Model, type SimpleStreamOptions, type StopReason, type ToolCall } from "@earendil-works/pi-ai";
|
|
6
6
|
declare class ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
|
|
7
7
|
constructor();
|
|
8
8
|
}
|
|
@@ -45,6 +45,7 @@ export type ProxyAssistantMessageEvent = {
|
|
|
45
45
|
} | {
|
|
46
46
|
type: "toolcall_end";
|
|
47
47
|
contentIndex: number;
|
|
48
|
+
toolCall: ToolCall;
|
|
48
49
|
} | {
|
|
49
50
|
type: "done";
|
|
50
51
|
reason: Extract<StopReason, "stop" | "length" | "toolUse">;
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,WAAW,EACX,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,KAAK,UAAU,EAEf,MAAM,uBAAuB,CAAC;AAG/B,cAAM,uBAAwB,SAAQ,WAAW,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;IACzF,cASC;CACD;AAED;;GAEG;AACH,MAAM,MAAM,0BAA0B,GACnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC9C;IACA,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAC3D,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,CAAC;AAEL,KAAK,8BAA8B,GAAG,IAAI,CACzC,mBAAmB,EACjB,aAAa,GACb,gBAAgB,GAChB,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,iBAAiB,CACnB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,8BAA8B;IACzE,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAqCD,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,GAAG,uBAAuB,CAqHrH","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@earendil-works/pi-ai\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"samplingParams\"\n\t| \"maxTokens\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tsamplingParams: options.samplingParams,\n\t\tmaxTokens: options.maxTokens,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"pending\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,WAAW,EACX,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,MAAM,uBAAuB,CAAC;AAG/B,cAAM,uBAAwB,SAAQ,WAAW,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;IACzF,cASC;CACD;AAED;;GAEG;AACH,MAAM,MAAM,0BAA0B,GACnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClE;IACA,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAC3D,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,CAAC;AAEL,KAAK,8BAA8B,GAAG,IAAI,CACzC,mBAAmB,EACjB,aAAa,GACb,gBAAgB,GAChB,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,iBAAiB,CACnB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,8BAA8B;IACzE,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAqCD,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,GAAG,uBAAuB,CAqHrH","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@earendil-works/pi-ai\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"samplingParams\"\n\t| \"maxTokens\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tsamplingParams: options.samplingParams,\n\t\tmaxTokens: options.maxTokens,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"pending\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tObject.assign(content, proxyEvent.toolCall);\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
package/dist/proxy.js
CHANGED
|
@@ -250,6 +250,7 @@ function processProxyEvent(proxyEvent, partial) {
|
|
|
250
250
|
case "toolcall_end": {
|
|
251
251
|
const content = partial.content[proxyEvent.contentIndex];
|
|
252
252
|
if (content?.type === "toolCall") {
|
|
253
|
+
Object.assign(content, proxyEvent.toolCall);
|
|
253
254
|
delete content.partialJson;
|
|
254
255
|
return {
|
|
255
256
|
type: "toolcall_end",
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@earendil-works/pi-ai\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"samplingParams\"\n\t| \"maxTokens\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tsamplingParams: options.samplingParams,\n\t\tmaxTokens: options.maxTokens,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"pending\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@earendil-works/pi-ai\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number; toolCall: ToolCall }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"samplingParams\"\n\t| \"maxTokens\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tsamplingParams: options.samplingParams,\n\t\tmaxTokens: options.maxTokens,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"pending\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tObject.assign(content, proxyEvent.toolCall);\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Entry } from "../harness/session/types.ts";
|
|
2
|
+
export type { ScanningReadable, ScanningReadableOptions, ScanningReadableSource, ScanningSearchTextProjector, ScanningSessionSearchHit, ScanningSessionSearchOptions, SessionSearchCandidate, } from "./scanning.ts";
|
|
3
|
+
export { createScanningSessionSearch, scanningEntries } from "./scanning.ts";
|
|
4
|
+
export interface SessionSearchOptions {
|
|
5
|
+
/** Restrict results to specific canonical entry types. */
|
|
6
|
+
readonly entryTypes?: readonly Entry["type"][];
|
|
7
|
+
/** Maximum number of hits to return. */
|
|
8
|
+
readonly limit?: number;
|
|
9
|
+
/** Abort signal for cancellation, e.g. search-as-you-type. */
|
|
10
|
+
readonly signal?: AbortSignal;
|
|
11
|
+
}
|
|
12
|
+
export interface SessionSearchHit {
|
|
13
|
+
/** Logical identifier of the session that owns the entry. */
|
|
14
|
+
readonly sessionId: string;
|
|
15
|
+
/** Logical identifier of the entry within that session. */
|
|
16
|
+
readonly entryId: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SessionSearch<T extends SessionSearchHit = SessionSearchHit> {
|
|
19
|
+
search(text: string, options?: SessionSearchOptions): AsyncIterable<T>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEzD,YAAY,EACX,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,2BAA2B,EAC3B,wBAAwB,EACxB,4BAA4B,EAC5B,sBAAsB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAE7E,MAAM,WAAW,oBAAoB;IACpC,0DAA0D;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/C,wCAAwC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAChC,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB;IAC3E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;CACvE","sourcesContent":["import type { Entry } from \"../harness/session/types.ts\";\n\nexport type {\n\tScanningReadable,\n\tScanningReadableOptions,\n\tScanningReadableSource,\n\tScanningSearchTextProjector,\n\tScanningSessionSearchHit,\n\tScanningSessionSearchOptions,\n\tSessionSearchCandidate,\n} from \"./scanning.ts\";\nexport { createScanningSessionSearch, scanningEntries } from \"./scanning.ts\";\n\nexport interface SessionSearchOptions {\n\t/** Restrict results to specific canonical entry types. */\n\treadonly entryTypes?: readonly Entry[\"type\"][];\n\t/** Maximum number of hits to return. */\n\treadonly limit?: number;\n\t/** Abort signal for cancellation, e.g. search-as-you-type. */\n\treadonly signal?: AbortSignal;\n}\n\nexport interface SessionSearchHit {\n\t/** Logical identifier of the session that owns the entry. */\n\treadonly sessionId: string;\n\t/** Logical identifier of the entry within that session. */\n\treadonly entryId: string;\n}\n\nexport interface SessionSearch<T extends SessionSearchHit = SessionSearchHit> {\n\tsearch(text: string, options?: SessionSearchOptions): AsyncIterable<T>;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC","sourcesContent":["import type { Entry } from \"../harness/session/types.ts\";\n\nexport type {\n\tScanningReadable,\n\tScanningReadableOptions,\n\tScanningReadableSource,\n\tScanningSearchTextProjector,\n\tScanningSessionSearchHit,\n\tScanningSessionSearchOptions,\n\tSessionSearchCandidate,\n} from \"./scanning.ts\";\nexport { createScanningSessionSearch, scanningEntries } from \"./scanning.ts\";\n\nexport interface SessionSearchOptions {\n\t/** Restrict results to specific canonical entry types. */\n\treadonly entryTypes?: readonly Entry[\"type\"][];\n\t/** Maximum number of hits to return. */\n\treadonly limit?: number;\n\t/** Abort signal for cancellation, e.g. search-as-you-type. */\n\treadonly signal?: AbortSignal;\n}\n\nexport interface SessionSearchHit {\n\t/** Logical identifier of the session that owns the entry. */\n\treadonly sessionId: string;\n\t/** Logical identifier of the entry within that session. */\n\treadonly entryId: string;\n}\n\nexport interface SessionSearch<T extends SessionSearchHit = SessionSearchHit> {\n\tsearch(text: string, options?: SessionSearchOptions): AsyncIterable<T>;\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Entry, SessionMetadata, SessionStorage } from "../harness/session/types.ts";
|
|
2
|
+
import type { SessionSearch, SessionSearchHit, SessionSearchOptions } from "./index.ts";
|
|
3
|
+
export interface SessionSearchCandidate {
|
|
4
|
+
readonly entryId: string;
|
|
5
|
+
readonly seq: number;
|
|
6
|
+
readonly type: Entry["type"];
|
|
7
|
+
readonly timestamp: number;
|
|
8
|
+
readonly text: string;
|
|
9
|
+
readonly fields?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export type ScanningReadable<TMetadata extends SessionMetadata = SessionMetadata> = Pick<SessionStorage<TMetadata>, "getMetadata" | "findEntries" | "getLabel">;
|
|
12
|
+
export type ScanningReadableSource<TMetadata extends SessionMetadata = SessionMetadata, TOptions = unknown> = (options?: TOptions) => AsyncIterable<ScanningReadable<TMetadata>>;
|
|
13
|
+
export type ScanningSearchTextProjector<TMetadata extends SessionMetadata = SessionMetadata> = (metadata: TMetadata, entry: Entry, label: string | undefined) => string;
|
|
14
|
+
export interface ScanningReadableOptions<TMetadata extends SessionMetadata = SessionMetadata> {
|
|
15
|
+
projectText?: ScanningSearchTextProjector<TMetadata>;
|
|
16
|
+
pageSize?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ScanningSessionSearchHit extends SessionSearchHit {
|
|
19
|
+
readonly timestamp: number;
|
|
20
|
+
readonly snippet: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ScanningSessionSearchOptions<TMetadata extends SessionMetadata = SessionMetadata, TSourceOptions = unknown, THit extends SessionSearchHit = ScanningSessionSearchHit> extends ScanningReadableOptions<TMetadata> {
|
|
23
|
+
sourceOptions?: (text: string, options: SessionSearchOptions) => TSourceOptions | undefined;
|
|
24
|
+
match?: (queryText: string, candidate: SessionSearchCandidate, metadata: TMetadata) => boolean;
|
|
25
|
+
createHit?: (metadata: TMetadata, candidate: SessionSearchCandidate) => THit;
|
|
26
|
+
}
|
|
27
|
+
export declare function scanningEntries<TMetadata extends SessionMetadata>(readable: ScanningReadable<TMetadata>, options?: ScanningReadableOptions<TMetadata>): AsyncIterable<SessionSearchCandidate>;
|
|
28
|
+
export declare function createScanningSessionSearch<TMetadata extends SessionMetadata, TSourceOptions = unknown, THit extends SessionSearchHit = ScanningSessionSearchHit>(source: readonly ScanningReadable<TMetadata>[] | ScanningReadableSource<TMetadata, TSourceOptions>, options?: ScanningSessionSearchOptions<TMetadata, TSourceOptions, THit>): SessionSearch<THit>;
|
|
29
|
+
//# sourceMappingURL=scanning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanning.d.ts","sourceRoot":"","sources":["../../src/search/scanning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,MAAM,gBAAgB,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe,IAAI,IAAI,CACvF,cAAc,CAAC,SAAS,CAAC,EACzB,aAAa,GAAG,aAAa,GAAG,UAAU,CAC1C,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe,EAAE,QAAQ,GAAG,OAAO,IAAI,CAC7G,OAAO,CAAC,EAAE,QAAQ,KACd,aAAa,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC;AAEhD,MAAM,MAAM,2BAA2B,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe,IAAI,CAC9F,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,GAAG,SAAS,KACrB,MAAM,CAAC;AAEZ,MAAM,WAAW,uBAAuB,CAAC,SAAS,SAAS,eAAe,GAAG,eAAe;IAC3F,WAAW,CAAC,EAAE,2BAA2B,CAAC,SAAS,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,wBAAyB,SAAQ,gBAAgB;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B,CAC5C,SAAS,SAAS,eAAe,GAAG,eAAe,EACnD,cAAc,GAAG,OAAO,EACxB,IAAI,SAAS,gBAAgB,GAAG,wBAAwB,CACvD,SAAQ,uBAAuB,CAAC,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,KAAK,cAAc,GAAG,SAAS,CAAC;IAC5F,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,sBAAsB,EAAE,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC;IAC/F,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAC7E;AA6CD,wBAAuB,eAAe,CAAC,SAAS,SAAS,eAAe,EACvE,QAAQ,EAAE,gBAAgB,CAAC,SAAS,CAAC,EACrC,OAAO,GAAE,uBAAuB,CAAC,SAAS,CAAM,GAC9C,aAAa,CAAC,sBAAsB,CAAC,CAEvC;AAuCD,wBAAgB,2BAA2B,CAC1C,SAAS,SAAS,eAAe,EACjC,cAAc,GAAG,OAAO,EACxB,IAAI,SAAS,gBAAgB,GAAG,wBAAwB,EAExD,MAAM,EAAE,SAAS,gBAAgB,CAAC,SAAS,CAAC,EAAE,GAAG,sBAAsB,CAAC,SAAS,EAAE,cAAc,CAAC,EAClG,OAAO,GAAE,4BAA4B,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAM,GACzE,aAAa,CAAC,IAAI,CAAC,CAkCrB","sourcesContent":["import type { Entry, SessionMetadata, SessionStorage } from \"../harness/session/types.ts\";\nimport type { SessionSearch, SessionSearchHit, SessionSearchOptions } from \"./index.ts\";\n\nexport interface SessionSearchCandidate {\n\treadonly entryId: string;\n\treadonly seq: number;\n\treadonly type: Entry[\"type\"];\n\treadonly timestamp: number;\n\treadonly text: string;\n\treadonly fields?: Record<string, unknown>;\n}\n\nexport type ScanningReadable<TMetadata extends SessionMetadata = SessionMetadata> = Pick<\n\tSessionStorage<TMetadata>,\n\t\"getMetadata\" | \"findEntries\" | \"getLabel\"\n>;\n\nexport type ScanningReadableSource<TMetadata extends SessionMetadata = SessionMetadata, TOptions = unknown> = (\n\toptions?: TOptions,\n) => AsyncIterable<ScanningReadable<TMetadata>>;\n\nexport type ScanningSearchTextProjector<TMetadata extends SessionMetadata = SessionMetadata> = (\n\tmetadata: TMetadata,\n\tentry: Entry,\n\tlabel: string | undefined,\n) => string;\n\nexport interface ScanningReadableOptions<TMetadata extends SessionMetadata = SessionMetadata> {\n\tprojectText?: ScanningSearchTextProjector<TMetadata>;\n\tpageSize?: number;\n}\n\nexport interface ScanningSessionSearchHit extends SessionSearchHit {\n\treadonly timestamp: number;\n\treadonly snippet: string;\n}\n\nexport interface ScanningSessionSearchOptions<\n\tTMetadata extends SessionMetadata = SessionMetadata,\n\tTSourceOptions = unknown,\n\tTHit extends SessionSearchHit = ScanningSessionSearchHit,\n> extends ScanningReadableOptions<TMetadata> {\n\tsourceOptions?: (text: string, options: SessionSearchOptions) => TSourceOptions | undefined;\n\tmatch?: (queryText: string, candidate: SessionSearchCandidate, metadata: TMetadata) => boolean;\n\tcreateHit?: (metadata: TMetadata, candidate: SessionSearchCandidate) => THit;\n}\n\nfunction defaultSearchText<TMetadata extends SessionMetadata>(\n\t_metadata: TMetadata,\n\tentry: Entry,\n\tlabel: string | undefined,\n): string {\n\treturn label === undefined ? JSON.stringify(entry) : `${JSON.stringify(entry)} ${label}`;\n}\n\nasync function* scanReadableEntries<TMetadata extends SessionMetadata>(\n\treadable: ScanningReadable<TMetadata>,\n\tmetadata: TMetadata,\n\toptions: ScanningReadableOptions<TMetadata>,\n\tquery: { afterSeq?: number; limit?: number; entryTypes?: readonly Entry[\"type\"][] } = {},\n): AsyncIterable<SessionSearchCandidate> {\n\tconst projectText = options.projectText ?? defaultSearchText;\n\tconst pageSize = query.limit ?? options.pageSize ?? 100;\n\tlet afterSeq = query.afterSeq ?? 0;\n\tconst entryTypes = query.entryTypes === undefined ? undefined : new Set(query.entryTypes);\n\twhile (true) {\n\t\tconst entries = await readable.findEntries({\n\t\t\torder: \"oldestFirst\",\n\t\t\tlimit: pageSize,\n\t\t\tcursor: { afterSeq },\n\t\t\ttype: query.entryTypes?.length === 1 ? query.entryTypes[0] : undefined,\n\t\t});\n\t\tif (entries.length === 0) break;\n\t\tfor (const entry of entries) {\n\t\t\tif (entryTypes !== undefined && !entryTypes.has(entry.type)) continue;\n\t\t\tconst label = await readable.getLabel(entry.id);\n\t\t\tyield {\n\t\t\t\tentryId: entry.id,\n\t\t\t\tseq: entry.seq,\n\t\t\t\ttype: entry.type,\n\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\ttext: projectText(metadata, entry, label),\n\t\t\t\tfields: label === undefined ? undefined : { label },\n\t\t\t};\n\t\t}\n\t\tafterSeq = entries[entries.length - 1]?.seq ?? afterSeq;\n\t\tif (entries.length < pageSize) break;\n\t}\n}\n\nexport async function* scanningEntries<TMetadata extends SessionMetadata>(\n\treadable: ScanningReadable<TMetadata>,\n\toptions: ScanningReadableOptions<TMetadata> = {},\n): AsyncIterable<SessionSearchCandidate> {\n\tyield* scanReadableEntries(readable, await readable.getMetadata(), options);\n}\n\nasync function* arraySource<TMetadata extends SessionMetadata>(\n\treadables: readonly ScanningReadable<TMetadata>[],\n): AsyncIterable<ScanningReadable<TMetadata>> {\n\tyield* readables;\n}\n\nfunction readablesFor<TMetadata extends SessionMetadata, TSourceOptions>(\n\tsource: readonly ScanningReadable<TMetadata>[] | ScanningReadableSource<TMetadata, TSourceOptions>,\n\toptions: TSourceOptions | undefined,\n): AsyncIterable<ScanningReadable<TMetadata>> {\n\treturn typeof source === \"function\" ? source(options) : arraySource(source);\n}\n\nfunction defaultMatch(queryText: string, candidate: SessionSearchCandidate): boolean {\n\treturn candidate.text.toLowerCase().includes(queryText);\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n\tif (!signal?.aborted) return;\n\tif (signal.reason instanceof Error) throw signal.reason;\n\tconst error = new Error(\"The operation was aborted\");\n\terror.name = \"AbortError\";\n\tthrow error;\n}\n\nfunction createDefaultScanningHit<TMetadata extends SessionMetadata>(\n\tmetadata: TMetadata,\n\tcandidate: SessionSearchCandidate,\n): ScanningSessionSearchHit {\n\treturn {\n\t\tsessionId: metadata.id,\n\t\tentryId: candidate.entryId,\n\t\ttimestamp: candidate.timestamp,\n\t\tsnippet: candidate.text,\n\t};\n}\n\nexport function createScanningSessionSearch<\n\tTMetadata extends SessionMetadata,\n\tTSourceOptions = unknown,\n\tTHit extends SessionSearchHit = ScanningSessionSearchHit,\n>(\n\tsource: readonly ScanningReadable<TMetadata>[] | ScanningReadableSource<TMetadata, TSourceOptions>,\n\toptions: ScanningSessionSearchOptions<TMetadata, TSourceOptions, THit> = {},\n): SessionSearch<THit> {\n\tconst createHit =\n\t\toptions.createHit ??\n\t\t((metadata: TMetadata, candidate: SessionSearchCandidate) =>\n\t\t\tcreateDefaultScanningHit(metadata, candidate) as unknown as THit);\n\treturn {\n\t\tasync *search(text: string, searchOptions: SessionSearchOptions = {}): AsyncIterable<THit> {\n\t\t\tconst normalizedText = text.trim().toLowerCase();\n\t\t\tif (!normalizedText || (searchOptions.limit !== undefined && searchOptions.limit <= 0)) return;\n\t\t\tif (searchOptions.entryTypes?.length === 0) return;\n\t\t\tlet hitCount = 0;\n\t\t\tconst seenSessionIds = new Set<string>();\n\t\t\tconst entryTypes = searchOptions.entryTypes === undefined ? undefined : new Set(searchOptions.entryTypes);\n\t\t\tconst sourceOptions = options.sourceOptions?.(normalizedText, searchOptions);\n\t\t\tfor await (const readable of readablesFor(source, sourceOptions)) {\n\t\t\t\tthrowIfAborted(searchOptions.signal);\n\t\t\t\tconst metadata = await readable.getMetadata();\n\t\t\t\tif (seenSessionIds.has(metadata.id)) throw new Error(`Duplicate sessionId: ${metadata.id}`);\n\t\t\t\tseenSessionIds.add(metadata.id);\n\t\t\t\tfor await (const candidate of scanReadableEntries(readable, metadata, options, {\n\t\t\t\t\tentryTypes: searchOptions.entryTypes,\n\t\t\t\t})) {\n\t\t\t\t\tthrowIfAborted(searchOptions.signal);\n\t\t\t\t\tif (entryTypes !== undefined && !entryTypes.has(candidate.type)) continue;\n\t\t\t\t\tconst matches =\n\t\t\t\t\t\toptions.match?.(normalizedText, candidate, metadata) ?? defaultMatch(normalizedText, candidate);\n\t\t\t\t\tif (!matches) continue;\n\t\t\t\t\tyield createHit(metadata, candidate);\n\t\t\t\t\thitCount += 1;\n\t\t\t\t\tif (searchOptions.limit !== undefined && hitCount >= searchOptions.limit) return;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
function defaultSearchText(_metadata, entry, label) {
|
|
2
|
+
return label === undefined ? JSON.stringify(entry) : `${JSON.stringify(entry)} ${label}`;
|
|
3
|
+
}
|
|
4
|
+
async function* scanReadableEntries(readable, metadata, options, query = {}) {
|
|
5
|
+
const projectText = options.projectText ?? defaultSearchText;
|
|
6
|
+
const pageSize = query.limit ?? options.pageSize ?? 100;
|
|
7
|
+
let afterSeq = query.afterSeq ?? 0;
|
|
8
|
+
const entryTypes = query.entryTypes === undefined ? undefined : new Set(query.entryTypes);
|
|
9
|
+
while (true) {
|
|
10
|
+
const entries = await readable.findEntries({
|
|
11
|
+
order: "oldestFirst",
|
|
12
|
+
limit: pageSize,
|
|
13
|
+
cursor: { afterSeq },
|
|
14
|
+
type: query.entryTypes?.length === 1 ? query.entryTypes[0] : undefined,
|
|
15
|
+
});
|
|
16
|
+
if (entries.length === 0)
|
|
17
|
+
break;
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if (entryTypes !== undefined && !entryTypes.has(entry.type))
|
|
20
|
+
continue;
|
|
21
|
+
const label = await readable.getLabel(entry.id);
|
|
22
|
+
yield {
|
|
23
|
+
entryId: entry.id,
|
|
24
|
+
seq: entry.seq,
|
|
25
|
+
type: entry.type,
|
|
26
|
+
timestamp: entry.timestamp,
|
|
27
|
+
text: projectText(metadata, entry, label),
|
|
28
|
+
fields: label === undefined ? undefined : { label },
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
afterSeq = entries[entries.length - 1]?.seq ?? afterSeq;
|
|
32
|
+
if (entries.length < pageSize)
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function* scanningEntries(readable, options = {}) {
|
|
37
|
+
yield* scanReadableEntries(readable, await readable.getMetadata(), options);
|
|
38
|
+
}
|
|
39
|
+
async function* arraySource(readables) {
|
|
40
|
+
yield* readables;
|
|
41
|
+
}
|
|
42
|
+
function readablesFor(source, options) {
|
|
43
|
+
return typeof source === "function" ? source(options) : arraySource(source);
|
|
44
|
+
}
|
|
45
|
+
function defaultMatch(queryText, candidate) {
|
|
46
|
+
return candidate.text.toLowerCase().includes(queryText);
|
|
47
|
+
}
|
|
48
|
+
function throwIfAborted(signal) {
|
|
49
|
+
if (!signal?.aborted)
|
|
50
|
+
return;
|
|
51
|
+
if (signal.reason instanceof Error)
|
|
52
|
+
throw signal.reason;
|
|
53
|
+
const error = new Error("The operation was aborted");
|
|
54
|
+
error.name = "AbortError";
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
function createDefaultScanningHit(metadata, candidate) {
|
|
58
|
+
return {
|
|
59
|
+
sessionId: metadata.id,
|
|
60
|
+
entryId: candidate.entryId,
|
|
61
|
+
timestamp: candidate.timestamp,
|
|
62
|
+
snippet: candidate.text,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function createScanningSessionSearch(source, options = {}) {
|
|
66
|
+
const createHit = options.createHit ??
|
|
67
|
+
((metadata, candidate) => createDefaultScanningHit(metadata, candidate));
|
|
68
|
+
return {
|
|
69
|
+
async *search(text, searchOptions = {}) {
|
|
70
|
+
const normalizedText = text.trim().toLowerCase();
|
|
71
|
+
if (!normalizedText || (searchOptions.limit !== undefined && searchOptions.limit <= 0))
|
|
72
|
+
return;
|
|
73
|
+
if (searchOptions.entryTypes?.length === 0)
|
|
74
|
+
return;
|
|
75
|
+
let hitCount = 0;
|
|
76
|
+
const seenSessionIds = new Set();
|
|
77
|
+
const entryTypes = searchOptions.entryTypes === undefined ? undefined : new Set(searchOptions.entryTypes);
|
|
78
|
+
const sourceOptions = options.sourceOptions?.(normalizedText, searchOptions);
|
|
79
|
+
for await (const readable of readablesFor(source, sourceOptions)) {
|
|
80
|
+
throwIfAborted(searchOptions.signal);
|
|
81
|
+
const metadata = await readable.getMetadata();
|
|
82
|
+
if (seenSessionIds.has(metadata.id))
|
|
83
|
+
throw new Error(`Duplicate sessionId: ${metadata.id}`);
|
|
84
|
+
seenSessionIds.add(metadata.id);
|
|
85
|
+
for await (const candidate of scanReadableEntries(readable, metadata, options, {
|
|
86
|
+
entryTypes: searchOptions.entryTypes,
|
|
87
|
+
})) {
|
|
88
|
+
throwIfAborted(searchOptions.signal);
|
|
89
|
+
if (entryTypes !== undefined && !entryTypes.has(candidate.type))
|
|
90
|
+
continue;
|
|
91
|
+
const matches = options.match?.(normalizedText, candidate, metadata) ?? defaultMatch(normalizedText, candidate);
|
|
92
|
+
if (!matches)
|
|
93
|
+
continue;
|
|
94
|
+
yield createHit(metadata, candidate);
|
|
95
|
+
hitCount += 1;
|
|
96
|
+
if (searchOptions.limit !== undefined && hitCount >= searchOptions.limit)
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=scanning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanning.js","sourceRoot":"","sources":["../../src/search/scanning.ts"],"names":[],"mappings":"AA+CA,SAAS,iBAAiB,CACzB,SAAoB,EACpB,KAAY,EACZ,KAAyB,EAChB;IACT,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;AAAA,CACzF;AAED,KAAK,SAAS,CAAC,CAAC,mBAAmB,CAClC,QAAqC,EACrC,QAAmB,EACnB,OAA2C,EAC3C,KAAK,GAAiF,EAAE,EAChD;IACxC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,iBAAiB,CAAC;IAC7D,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ,IAAI,GAAG,CAAC;IACxD,IAAI,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1F,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;YAC1C,KAAK,EAAE,aAAa;YACpB,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,EAAE,QAAQ,EAAE;YACpB,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;SACtE,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM;QAChC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YACtE,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChD,MAAM;gBACL,OAAO,EAAE,KAAK,CAAC,EAAE;gBACjB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,IAAI,EAAE,WAAW,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC;gBACzC,MAAM,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE;aACnD,CAAC;QACH,CAAC;QACD,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC;QACxD,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ;YAAE,MAAM;IACtC,CAAC;AAAA,CACD;AAED,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,eAAe,CACrC,QAAqC,EACrC,OAAO,GAAuC,EAAE,EACR;IACxC,KAAK,CAAC,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,QAAQ,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;AAAA,CAC5E;AAED,KAAK,SAAS,CAAC,CAAC,WAAW,CAC1B,SAAiD,EACJ;IAC7C,KAAK,CAAC,CAAC,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,YAAY,CACpB,MAAkG,EAClG,OAAmC,EACU;IAC7C,OAAO,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAAA,CAC5E;AAED,SAAS,YAAY,CAAC,SAAiB,EAAE,SAAiC,EAAW;IACpF,OAAO,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAAA,CACxD;AAED,SAAS,cAAc,CAAC,MAA+B,EAAQ;IAC9D,IAAI,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO;IAC7B,IAAI,MAAM,CAAC,MAAM,YAAY,KAAK;QAAE,MAAM,MAAM,CAAC,MAAM,CAAC;IACxD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACrD,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC;IAC1B,MAAM,KAAK,CAAC;AAAA,CACZ;AAED,SAAS,wBAAwB,CAChC,QAAmB,EACnB,SAAiC,EACN;IAC3B,OAAO;QACN,SAAS,EAAE,QAAQ,CAAC,EAAE;QACtB,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,SAAS,EAAE,SAAS,CAAC,SAAS;QAC9B,OAAO,EAAE,SAAS,CAAC,IAAI;KACvB,CAAC;AAAA,CACF;AAED,MAAM,UAAU,2BAA2B,CAK1C,MAAkG,EAClG,OAAO,GAAkE,EAAE,EACrD;IACtB,MAAM,SAAS,GACd,OAAO,CAAC,SAAS;QACjB,CAAC,CAAC,QAAmB,EAAE,SAAiC,EAAE,EAAE,CAC3D,wBAAwB,CAAC,QAAQ,EAAE,SAAS,CAAoB,CAAC,CAAC;IACpE,OAAO;QACN,KAAK,CAAC,CAAC,MAAM,CAAC,IAAY,EAAE,aAAa,GAAyB,EAAE,EAAuB;YAC1F,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,CAAC,KAAK,KAAK,SAAS,IAAI,aAAa,CAAC,KAAK,IAAI,CAAC,CAAC;gBAAE,OAAO;YAC/F,IAAI,aAAa,CAAC,UAAU,EAAE,MAAM,KAAK,CAAC;gBAAE,OAAO;YACnD,IAAI,QAAQ,GAAG,CAAC,CAAC;YACjB,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;YACzC,MAAM,UAAU,GAAG,aAAa,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YAC1G,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,cAAc,EAAE,aAAa,CAAC,CAAC;YAC7E,IAAI,KAAK,EAAE,MAAM,QAAQ,IAAI,YAAY,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC;gBAClE,cAAc,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBACrC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;gBAC9C,IAAI,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC5F,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAChC,IAAI,KAAK,EAAE,MAAM,SAAS,IAAI,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE;oBAC9E,UAAU,EAAE,aAAa,CAAC,UAAU;iBACpC,CAAC,EAAE,CAAC;oBACJ,cAAc,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;oBACrC,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;wBAAE,SAAS;oBAC1E,MAAM,OAAO,GACZ,OAAO,CAAC,KAAK,EAAE,CAAC,cAAc,EAAE,SAAS,EAAE,QAAQ,CAAC,IAAI,YAAY,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;oBACjG,IAAI,CAAC,OAAO;wBAAE,SAAS;oBACvB,MAAM,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;oBACrC,QAAQ,IAAI,CAAC,CAAC;oBACd,IAAI,aAAa,CAAC,KAAK,KAAK,SAAS,IAAI,QAAQ,IAAI,aAAa,CAAC,KAAK;wBAAE,OAAO;gBAClF,CAAC;YACF,CAAC;QAAA,CACD;KACD,CAAC;AAAA,CACF","sourcesContent":["import type { Entry, SessionMetadata, SessionStorage } from \"../harness/session/types.ts\";\nimport type { SessionSearch, SessionSearchHit, SessionSearchOptions } from \"./index.ts\";\n\nexport interface SessionSearchCandidate {\n\treadonly entryId: string;\n\treadonly seq: number;\n\treadonly type: Entry[\"type\"];\n\treadonly timestamp: number;\n\treadonly text: string;\n\treadonly fields?: Record<string, unknown>;\n}\n\nexport type ScanningReadable<TMetadata extends SessionMetadata = SessionMetadata> = Pick<\n\tSessionStorage<TMetadata>,\n\t\"getMetadata\" | \"findEntries\" | \"getLabel\"\n>;\n\nexport type ScanningReadableSource<TMetadata extends SessionMetadata = SessionMetadata, TOptions = unknown> = (\n\toptions?: TOptions,\n) => AsyncIterable<ScanningReadable<TMetadata>>;\n\nexport type ScanningSearchTextProjector<TMetadata extends SessionMetadata = SessionMetadata> = (\n\tmetadata: TMetadata,\n\tentry: Entry,\n\tlabel: string | undefined,\n) => string;\n\nexport interface ScanningReadableOptions<TMetadata extends SessionMetadata = SessionMetadata> {\n\tprojectText?: ScanningSearchTextProjector<TMetadata>;\n\tpageSize?: number;\n}\n\nexport interface ScanningSessionSearchHit extends SessionSearchHit {\n\treadonly timestamp: number;\n\treadonly snippet: string;\n}\n\nexport interface ScanningSessionSearchOptions<\n\tTMetadata extends SessionMetadata = SessionMetadata,\n\tTSourceOptions = unknown,\n\tTHit extends SessionSearchHit = ScanningSessionSearchHit,\n> extends ScanningReadableOptions<TMetadata> {\n\tsourceOptions?: (text: string, options: SessionSearchOptions) => TSourceOptions | undefined;\n\tmatch?: (queryText: string, candidate: SessionSearchCandidate, metadata: TMetadata) => boolean;\n\tcreateHit?: (metadata: TMetadata, candidate: SessionSearchCandidate) => THit;\n}\n\nfunction defaultSearchText<TMetadata extends SessionMetadata>(\n\t_metadata: TMetadata,\n\tentry: Entry,\n\tlabel: string | undefined,\n): string {\n\treturn label === undefined ? JSON.stringify(entry) : `${JSON.stringify(entry)} ${label}`;\n}\n\nasync function* scanReadableEntries<TMetadata extends SessionMetadata>(\n\treadable: ScanningReadable<TMetadata>,\n\tmetadata: TMetadata,\n\toptions: ScanningReadableOptions<TMetadata>,\n\tquery: { afterSeq?: number; limit?: number; entryTypes?: readonly Entry[\"type\"][] } = {},\n): AsyncIterable<SessionSearchCandidate> {\n\tconst projectText = options.projectText ?? defaultSearchText;\n\tconst pageSize = query.limit ?? options.pageSize ?? 100;\n\tlet afterSeq = query.afterSeq ?? 0;\n\tconst entryTypes = query.entryTypes === undefined ? undefined : new Set(query.entryTypes);\n\twhile (true) {\n\t\tconst entries = await readable.findEntries({\n\t\t\torder: \"oldestFirst\",\n\t\t\tlimit: pageSize,\n\t\t\tcursor: { afterSeq },\n\t\t\ttype: query.entryTypes?.length === 1 ? query.entryTypes[0] : undefined,\n\t\t});\n\t\tif (entries.length === 0) break;\n\t\tfor (const entry of entries) {\n\t\t\tif (entryTypes !== undefined && !entryTypes.has(entry.type)) continue;\n\t\t\tconst label = await readable.getLabel(entry.id);\n\t\t\tyield {\n\t\t\t\tentryId: entry.id,\n\t\t\t\tseq: entry.seq,\n\t\t\t\ttype: entry.type,\n\t\t\t\ttimestamp: entry.timestamp,\n\t\t\t\ttext: projectText(metadata, entry, label),\n\t\t\t\tfields: label === undefined ? undefined : { label },\n\t\t\t};\n\t\t}\n\t\tafterSeq = entries[entries.length - 1]?.seq ?? afterSeq;\n\t\tif (entries.length < pageSize) break;\n\t}\n}\n\nexport async function* scanningEntries<TMetadata extends SessionMetadata>(\n\treadable: ScanningReadable<TMetadata>,\n\toptions: ScanningReadableOptions<TMetadata> = {},\n): AsyncIterable<SessionSearchCandidate> {\n\tyield* scanReadableEntries(readable, await readable.getMetadata(), options);\n}\n\nasync function* arraySource<TMetadata extends SessionMetadata>(\n\treadables: readonly ScanningReadable<TMetadata>[],\n): AsyncIterable<ScanningReadable<TMetadata>> {\n\tyield* readables;\n}\n\nfunction readablesFor<TMetadata extends SessionMetadata, TSourceOptions>(\n\tsource: readonly ScanningReadable<TMetadata>[] | ScanningReadableSource<TMetadata, TSourceOptions>,\n\toptions: TSourceOptions | undefined,\n): AsyncIterable<ScanningReadable<TMetadata>> {\n\treturn typeof source === \"function\" ? source(options) : arraySource(source);\n}\n\nfunction defaultMatch(queryText: string, candidate: SessionSearchCandidate): boolean {\n\treturn candidate.text.toLowerCase().includes(queryText);\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n\tif (!signal?.aborted) return;\n\tif (signal.reason instanceof Error) throw signal.reason;\n\tconst error = new Error(\"The operation was aborted\");\n\terror.name = \"AbortError\";\n\tthrow error;\n}\n\nfunction createDefaultScanningHit<TMetadata extends SessionMetadata>(\n\tmetadata: TMetadata,\n\tcandidate: SessionSearchCandidate,\n): ScanningSessionSearchHit {\n\treturn {\n\t\tsessionId: metadata.id,\n\t\tentryId: candidate.entryId,\n\t\ttimestamp: candidate.timestamp,\n\t\tsnippet: candidate.text,\n\t};\n}\n\nexport function createScanningSessionSearch<\n\tTMetadata extends SessionMetadata,\n\tTSourceOptions = unknown,\n\tTHit extends SessionSearchHit = ScanningSessionSearchHit,\n>(\n\tsource: readonly ScanningReadable<TMetadata>[] | ScanningReadableSource<TMetadata, TSourceOptions>,\n\toptions: ScanningSessionSearchOptions<TMetadata, TSourceOptions, THit> = {},\n): SessionSearch<THit> {\n\tconst createHit =\n\t\toptions.createHit ??\n\t\t((metadata: TMetadata, candidate: SessionSearchCandidate) =>\n\t\t\tcreateDefaultScanningHit(metadata, candidate) as unknown as THit);\n\treturn {\n\t\tasync *search(text: string, searchOptions: SessionSearchOptions = {}): AsyncIterable<THit> {\n\t\t\tconst normalizedText = text.trim().toLowerCase();\n\t\t\tif (!normalizedText || (searchOptions.limit !== undefined && searchOptions.limit <= 0)) return;\n\t\t\tif (searchOptions.entryTypes?.length === 0) return;\n\t\t\tlet hitCount = 0;\n\t\t\tconst seenSessionIds = new Set<string>();\n\t\t\tconst entryTypes = searchOptions.entryTypes === undefined ? undefined : new Set(searchOptions.entryTypes);\n\t\t\tconst sourceOptions = options.sourceOptions?.(normalizedText, searchOptions);\n\t\t\tfor await (const readable of readablesFor(source, sourceOptions)) {\n\t\t\t\tthrowIfAborted(searchOptions.signal);\n\t\t\t\tconst metadata = await readable.getMetadata();\n\t\t\t\tif (seenSessionIds.has(metadata.id)) throw new Error(`Duplicate sessionId: ${metadata.id}`);\n\t\t\t\tseenSessionIds.add(metadata.id);\n\t\t\t\tfor await (const candidate of scanReadableEntries(readable, metadata, options, {\n\t\t\t\t\tentryTypes: searchOptions.entryTypes,\n\t\t\t\t})) {\n\t\t\t\t\tthrowIfAborted(searchOptions.signal);\n\t\t\t\t\tif (entryTypes !== undefined && !entryTypes.has(candidate.type)) continue;\n\t\t\t\t\tconst matches =\n\t\t\t\t\t\toptions.match?.(normalizedText, candidate, metadata) ?? defaultMatch(normalizedText, candidate);\n\t\t\t\t\tif (!matches) continue;\n\t\t\t\t\tyield createHit(metadata, candidate);\n\t\t\t\t\thitCount += 1;\n\t\t\t\t\tif (searchOptions.limit !== undefined && hitCount >= searchOptions.limit) return;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
|