@inflexa-ai/harness 0.41.2 → 0.42.0
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/agents/conversation-agent.js +3 -0
- package/dist/agents/report-session-agent.d.ts +2 -2
- package/dist/agents/report-session-agent.js +4 -0
- package/dist/app/chat-turn.d.ts +0 -4
- package/dist/app/chat-turn.js +39 -25
- package/dist/app/message-assembly.d.ts +2 -2
- package/dist/app/message-assembly.js +1 -1
- package/dist/contracts/chat-events.d.ts +12 -5
- package/dist/contracts/chat-events.js +3 -3
- package/dist/contracts/chat-frame.d.ts +40 -0
- package/dist/contracts/chat-frame.js +166 -0
- package/dist/contracts/chat-parts.d.ts +15 -3
- package/dist/contracts/chat-parts.js +2 -2
- package/dist/contracts/index.d.ts +6 -4
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/message.d.ts +7 -5
- package/dist/contracts/message.js +1 -1
- package/dist/contracts/part-registry.d.ts +6 -6
- package/dist/contracts/schemas/chat-events.d.ts +2 -2
- package/dist/contracts/schemas/chat-events.js +2 -2
- package/dist/contracts/schemas/chat-parts.d.ts +34 -2
- package/dist/contracts/schemas/chat-parts.js +9 -3
- package/dist/contracts/schemas/index.d.ts +2 -2
- package/dist/contracts/schemas/index.js +2 -2
- package/dist/execution/run-event-parts.d.ts +4 -4
- package/dist/execution/run-event-parts.js +0 -0
- package/dist/execution/run-event-stream.d.ts +2 -2
- package/dist/index.d.ts +9 -6
- package/dist/index.js +3 -2
- package/dist/lib/page-capture.d.ts +27 -9
- package/dist/lib/page-capture.js +81 -33
- package/dist/loop/compaction.d.ts +8 -3
- package/dist/loop/run-agent.d.ts +11 -0
- package/dist/loop/run-agent.js +62 -35
- package/dist/loop/types.d.ts +3 -0
- package/dist/memory/ai-sdk-message-storage.d.ts +18 -3
- package/dist/memory/ai-sdk-message-storage.js +23 -1
- package/dist/memory/conversation-display-recorder.d.ts +7 -1
- package/dist/memory/conversation-display-recorder.js +59 -119
- package/dist/memory/conversation-display-replay.d.ts +3 -3
- package/dist/memory/conversation-display-replay.js +7 -21
- package/dist/memory/conversation-display-storage.d.ts +10 -10
- package/dist/memory/conversation-display-storage.js +9 -8
- package/dist/memory/conversation-view.d.ts +5 -4
- package/dist/memory/conversation-view.js +14 -18
- package/dist/memory/count-tokens.js +1 -0
- package/dist/memory/thread-store.d.ts +9 -2
- package/dist/memory/thread-store.js +8 -2
- package/dist/prompts/compaction.d.ts +2 -2
- package/dist/prompts/compaction.js +2 -2
- package/dist/prompts/report-session.d.ts +1 -1
- package/dist/prompts/report-session.js +40 -28
- package/dist/report-render/views/block-mark.d.ts +8 -0
- package/dist/report-render/views/block-mark.js +10 -0
- package/dist/report-render/views/chart-view.js +2 -1
- package/dist/report-render/views/prose.js +10 -6
- package/dist/report-render/views/values.js +5 -4
- package/dist/state/migrations/20260927180000_thread_title_set_by_user.d.ts +6 -0
- package/dist/state/migrations/20260927180000_thread_title_set_by_user.js +10 -0
- package/dist/state/migrations/index.js +2 -0
- package/dist/tools/report-authoring/authoring-tools.d.ts +16 -5
- package/dist/tools/report-authoring/authoring-tools.js +52 -24
- package/dist/tools/report-session/examine-page.d.ts +29 -14
- package/dist/tools/report-session/examine-page.js +40 -16
- package/dist/tools/report-session/list-artifacts.d.ts +23 -10
- package/dist/tools/report-session/list-artifacts.js +51 -31
- package/dist/tools/report-session/page-faults.d.ts +29 -0
- package/dist/tools/report-session/page-faults.js +48 -0
- package/dist/tools/report-session/preview-report.d.ts +9 -2
- package/dist/tools/report-session/preview-report.js +13 -3
- package/dist/tools/report-session/record-version.d.ts +5 -1
- package/dist/tools/report-session/record-version.js +4 -3
- package/package.json +1 -1
|
@@ -44,6 +44,8 @@ import { createResolveCitationTool } from "../tools/research/resolve-citation.js
|
|
|
44
44
|
export const CONVERSATION_AGENT_ID = "conversation-agent";
|
|
45
45
|
/** Runaway guard — heavy tool-driving turns need generous headroom. */
|
|
46
46
|
const CONVERSATION_MAX_ITERATIONS = 200;
|
|
47
|
+
/** Compaction budgets, in the input tokens of a request. */
|
|
48
|
+
const CONVERSATION_COMPACTION = { turnStartBudget: 150_000, budget: 200_000 };
|
|
47
49
|
/** Build the conversation `AgentDefinition` with every tool fully dep-bound. */
|
|
48
50
|
export function createConversationAgent(deps) {
|
|
49
51
|
const { provider, pool, embedding, workspaceFs, model, utilityProvider, utilityModel, executeAnalysisWorkflow, runAuthorizer, runLauncher, bioKeys, chrome, resourcePolicy, hostTools, refStorePath, farmLockFile, imagePackagesFile, readPoolInventory, usageRecorder, toolOutputStore, citationResolver, } = deps;
|
|
@@ -195,5 +197,6 @@ export function createConversationAgent(deps) {
|
|
|
195
197
|
model,
|
|
196
198
|
tools,
|
|
197
199
|
maxIterations: CONVERSATION_MAX_ITERATIONS,
|
|
200
|
+
compaction: CONVERSATION_COMPACTION,
|
|
198
201
|
};
|
|
199
202
|
}
|
|
@@ -77,8 +77,8 @@ export interface ReportSessionAgentDeps {
|
|
|
77
77
|
* Omitted, the tool derives nothing, the same as an absent sandbox client.
|
|
78
78
|
*/
|
|
79
79
|
readonly runAuthorizer?: RunAuthorizer;
|
|
80
|
-
/** Thread
|
|
81
|
-
readonly threads: Pick<ThreadStore, "getThread">;
|
|
80
|
+
/** Thread store -- the record tool reads the anchor of the report thread, and the preview tool names it. */
|
|
81
|
+
readonly threads: Pick<ThreadStore, "getThread" | "setAutoTitle">;
|
|
82
82
|
/** Headless-Chrome config -- the eyes tool opens the rendered page. */
|
|
83
83
|
readonly chrome: ChromeConfig;
|
|
84
84
|
/**
|
|
@@ -37,6 +37,8 @@ export const REPORT_SESSION_AGENT_ID = "report-session";
|
|
|
37
37
|
* gets the headroom of the report runner (REPORT_AGENT_MAX_STEPS).
|
|
38
38
|
*/
|
|
39
39
|
const REPORT_SESSION_MAX_ITERATIONS = 200;
|
|
40
|
+
/** A session is one long turn that holds page captures, thus it compacts only during the turn, at a higher budget. */
|
|
41
|
+
const REPORT_SESSION_COMPACTION = { budget: 250_000 };
|
|
40
42
|
/** Build the report `AgentDefinition` with every tool bound to its deps. */
|
|
41
43
|
export function createReportSessionAgent(deps) {
|
|
42
44
|
const { model, pool, embedding, workspaceFs, gateway, resolveWorkspaceRoot, store, threads, chrome, eyes, makeResolver, resolvePageAsset, logger } = deps;
|
|
@@ -87,6 +89,7 @@ export function createReportSessionAgent(deps) {
|
|
|
87
89
|
createPreviewReportTool({
|
|
88
90
|
gateway,
|
|
89
91
|
resolveWorkspaceRoot,
|
|
92
|
+
threads,
|
|
90
93
|
...(makeResolver ? { makeResolver } : {}),
|
|
91
94
|
...(resolvePageAsset ? { resolvePageAsset } : {}),
|
|
92
95
|
...(makeSessionPages ? { makeSessionPages } : {}),
|
|
@@ -122,5 +125,6 @@ export function createReportSessionAgent(deps) {
|
|
|
122
125
|
model,
|
|
123
126
|
tools,
|
|
124
127
|
maxIterations: REPORT_SESSION_MAX_ITERATIONS,
|
|
128
|
+
compaction: REPORT_SESSION_COMPACTION,
|
|
125
129
|
};
|
|
126
130
|
}
|
package/dist/app/chat-turn.d.ts
CHANGED
|
@@ -49,8 +49,6 @@ export type PrepareChatTurnResult = ({
|
|
|
49
49
|
* inside {@link assembleMessages} (applied once to the new user input only).
|
|
50
50
|
*/
|
|
51
51
|
export declare function prepareChatTurn(deps: PrepareChatTurnDeps, params: PrepareChatTurnParams): Promise<PrepareChatTurnResult>;
|
|
52
|
-
/** The root loop of a chat turn compacts its view past this estimate, in tokens. */
|
|
53
|
-
export declare const DEFAULT_CONVERSATION_BUDGET = 150000;
|
|
54
52
|
export interface RunChatTurnDeps extends PrepareChatTurnDeps {
|
|
55
53
|
/** The agent of a turn comes from the thread type, which only the preparation knows. */
|
|
56
54
|
readonly agents: ThreadAgentResolver;
|
|
@@ -82,8 +80,6 @@ export interface RunOpenChatTurnParams {
|
|
|
82
80
|
readonly startedAtMs?: number;
|
|
83
81
|
/** The cache policy of the root loop. Absent gives {@link CONVERSATION_PROMPT_CACHE}. */
|
|
84
82
|
readonly promptCache?: PromptCachePolicy;
|
|
85
|
-
/** The budget of the view of the root loop. Absent gives {@link DEFAULT_CONVERSATION_BUDGET}. */
|
|
86
|
-
readonly conversationBudget?: number;
|
|
87
83
|
}
|
|
88
84
|
/** The values of one whole turn. */
|
|
89
85
|
export type RunChatTurnParams = OpenChatTurnParams & RunOpenChatTurnParams;
|
package/dist/app/chat-turn.js
CHANGED
|
@@ -73,24 +73,23 @@ export async function prepareChatTurn(deps, params) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
else if (!existing.title || existing.title.length === 0) {
|
|
76
|
-
unwrapOrThrow(await store.
|
|
76
|
+
unwrapOrThrow(await store.setAutoTitle(threadId, deriveThreadTitle(userInput)));
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
catch (err) {
|
|
80
80
|
logger.warn("title-seed failed (non-fatal)", logger.errorFields(err));
|
|
81
81
|
}
|
|
82
|
-
const
|
|
83
|
-
const { messages, userMessage, contextRecords } = await assembleMessages({
|
|
82
|
+
const assembled = await assembleMessages({
|
|
84
83
|
threadId,
|
|
85
84
|
threadType,
|
|
86
85
|
analysisId,
|
|
87
86
|
userInput,
|
|
88
87
|
...(await readTurnContext(pool, analysisId)),
|
|
89
|
-
history,
|
|
88
|
+
history: createThreadHistory(pool),
|
|
90
89
|
workingMemory: createWorkingMemory(pool),
|
|
91
90
|
...(deps.logger ? { logger: deps.logger } : {}),
|
|
92
91
|
});
|
|
93
|
-
return { kind: "ok", threadType,
|
|
92
|
+
return { kind: "ok", threadType, ...assembled };
|
|
94
93
|
}
|
|
95
94
|
/** The analysis context and the run activity of a turn. A failed read gives the fallback of its kind. */
|
|
96
95
|
async function readTurnContext(pool, analysisId) {
|
|
@@ -98,8 +97,6 @@ async function readTurnContext(pool, analysisId) {
|
|
|
98
97
|
const runActivityContext = await queryNonTerminalRunsByAnalysis(pool, analysisId, RUN_ACTIVITY_DETAIL_LIMIT).match((activity) => renderRunActivity(activity), () => renderRunActivityUnavailable());
|
|
99
98
|
return { analysisContext: analysisState?.context ?? null, runActivityContext };
|
|
100
99
|
}
|
|
101
|
-
/** The root loop of a chat turn compacts its view past this estimate, in tokens. */
|
|
102
|
-
export const DEFAULT_CONVERSATION_BUDGET = 150_000;
|
|
103
100
|
/**
|
|
104
101
|
* Open one chat turn: prepare it and resolve its agent. A refusal comes back before any row of the
|
|
105
102
|
* turn exists, thus a host can answer it before it starts a stream.
|
|
@@ -142,22 +139,18 @@ async function runOpenTurn(deps, turn, prepared, agent, params) {
|
|
|
142
139
|
const history = createThreadHistory(deps.pool, deps.logger);
|
|
143
140
|
const recorder = createConversationDisplayRecorder({
|
|
144
141
|
userText: userTextOf(prepared.userMessage),
|
|
145
|
-
|
|
142
|
+
agentId: agent.id,
|
|
146
143
|
sink: params.emit,
|
|
147
144
|
});
|
|
148
145
|
// The groups that did not land yet, in the order of the turn. A failed write keeps them for the next write.
|
|
149
|
-
let pending = [
|
|
150
|
-
{
|
|
151
|
-
modelMessages: [prepared.userMessage, ...prepared.contextRecords],
|
|
152
|
-
displayMessages: recorder.takeOpening(),
|
|
153
|
-
...(params.author === undefined ? {} : { author: params.author }),
|
|
154
|
-
},
|
|
155
|
-
];
|
|
146
|
+
let pending = [];
|
|
156
147
|
let startSeq;
|
|
157
148
|
let storeError;
|
|
149
|
+
const opened = () => startSeq !== undefined || pending.length > 0;
|
|
158
150
|
// A store fault never stops the turn: the error rides the result.
|
|
159
151
|
const flush = async (close) => {
|
|
160
|
-
|
|
152
|
+
// A turn that ends before its user message was sent has no rows to close.
|
|
153
|
+
if (!opened() || (pending.length === 0 && close === undefined))
|
|
161
154
|
return;
|
|
162
155
|
const closing = close === undefined ? {} : { close };
|
|
163
156
|
const write = startSeq === undefined ? { opening: pending[0], rounds: pending.slice(1), ...closing } : { startSeq, rounds: pending, ...closing };
|
|
@@ -170,12 +163,32 @@ async function runOpenTurn(deps, turn, prepared, agent, params) {
|
|
|
170
163
|
logger.warn("chat turn write failed", { threadId: turn.threadId, op: error.op, ...logger.errorFields(error.cause) });
|
|
171
164
|
});
|
|
172
165
|
};
|
|
173
|
-
|
|
166
|
+
const storeRound = async (round) => {
|
|
167
|
+
if (!opened() && round.messages[0] !== prepared.userMessage) {
|
|
168
|
+
// A turn-start compaction comes before the user message, thus its rows land before the turn opens. A later
|
|
169
|
+
// write cannot keep that order, thus a failed write is not tried again, and the next turn compacts again.
|
|
170
|
+
const appended = await history.appendTurn(turn.threadId, { modelMessages: round.messages, displayMessages: recorder.takeRound(round.messages) });
|
|
171
|
+
if (appended.isErr()) {
|
|
172
|
+
logger.warn("chat turn compaction write failed", {
|
|
173
|
+
threadId: turn.threadId,
|
|
174
|
+
op: appended.error.op,
|
|
175
|
+
...logger.errorFields(appended.error.cause),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const author = params.author === undefined ? {} : { author: params.author };
|
|
181
|
+
pending.push(opened()
|
|
182
|
+
? { modelMessages: round.messages, displayMessages: recorder.takeRound(round.messages) }
|
|
183
|
+
: { modelMessages: round.messages, displayMessages: recorder.takeOpening(), ...author });
|
|
184
|
+
await flush();
|
|
185
|
+
};
|
|
174
186
|
const { ask } = params;
|
|
187
|
+
const compaction = compactionPolicy(deps, turn.analysisId, params, prepared.threadType, agent, recorder.emit);
|
|
175
188
|
let outcome;
|
|
176
189
|
let fallbackText;
|
|
177
190
|
try {
|
|
178
|
-
const run = await runAgent(agent, prepared.
|
|
191
|
+
const run = await runAgent(agent, prepared.history, session, {
|
|
179
192
|
provider: params.chat(recorder.emit),
|
|
180
193
|
signal: params.signal,
|
|
181
194
|
emit: recorder.emit,
|
|
@@ -183,17 +196,16 @@ async function runOpenTurn(deps, turn, prepared, agent, params) {
|
|
|
183
196
|
usageRecorder: params.usageRecorder,
|
|
184
197
|
toolOutputStore: createToolOutputStore(deps.pool),
|
|
185
198
|
promptCache: params.promptCache ?? CONVERSATION_PROMPT_CACHE,
|
|
186
|
-
|
|
199
|
+
turnInput: [prepared.userMessage, ...prepared.contextRecords],
|
|
200
|
+
...(compaction === undefined ? {} : { compaction }),
|
|
187
201
|
...(deps.logger === undefined ? {} : { logger: deps.logger }),
|
|
188
202
|
...(ask === undefined ? {} : { ask: (request) => ask(request, recorder.emit) }),
|
|
189
|
-
onRound:
|
|
190
|
-
pending.push({ modelMessages: round.messages, displayMessages: recorder.takeRound(round.messages) });
|
|
191
|
-
await flush();
|
|
192
|
-
},
|
|
203
|
+
onRound: storeRound,
|
|
193
204
|
});
|
|
194
205
|
outcome = run.finish.reason === "aborted" ? { status: "aborted", finish: run.finish } : { status: "done", finish: run.finish };
|
|
195
206
|
// An abort can end the run inside an exchange, and the text of an exchange is a summary, and no reply.
|
|
196
|
-
|
|
207
|
+
// The history ends on the reply of the last turn, thus only the messages of this run can give the text.
|
|
208
|
+
fallbackText = finalText(run.messages.slice(prepared.history.length).filter((message) => compactionExchangeOf(message) === undefined));
|
|
197
209
|
}
|
|
198
210
|
catch (cause) {
|
|
199
211
|
// A provider failure that races an abort stays a failure, thus both facts must hold.
|
|
@@ -226,11 +238,13 @@ function userTextOf(message) {
|
|
|
226
238
|
}
|
|
227
239
|
const WORKING_MEMORY_TOOL_ID = "update_working_memory";
|
|
228
240
|
function compactionPolicy(deps, analysisId, params, threadType, agent, emit) {
|
|
241
|
+
if (agent.compaction === undefined)
|
|
242
|
+
return undefined;
|
|
229
243
|
// A report thread reads a frozen copy of the working memory, thus its agent declares no memory tool.
|
|
230
244
|
const remembers = agent.tools.some((tool) => tool.id === WORKING_MEMORY_TOOL_ID);
|
|
231
245
|
const workingMemory = createWorkingMemory(deps.pool);
|
|
232
246
|
return {
|
|
233
|
-
|
|
247
|
+
...agent.compaction,
|
|
234
248
|
// A streaming provider sends each text delta with no source, thus a delta of the summary would show as a reply.
|
|
235
249
|
provider: params.chat((event) => (event.type === "text-delta" ? undefined : emit(event))),
|
|
236
250
|
request: remembers ? MEMORY_COMPACTION_REQUEST : SUMMARY_COMPACTION_REQUEST,
|
|
@@ -33,8 +33,8 @@ export interface AssembleMessagesArgs {
|
|
|
33
33
|
readonly logger?: Logger;
|
|
34
34
|
}
|
|
35
35
|
export interface AssembledMessages {
|
|
36
|
-
/** The
|
|
37
|
-
readonly
|
|
36
|
+
/** The view of the thread before the turn. */
|
|
37
|
+
readonly history: LoopMessage[];
|
|
38
38
|
/** The sanitized user input as its own message — the genuine turn start. */
|
|
39
39
|
readonly userMessage: ModelMessage;
|
|
40
40
|
/** The context records after the user message. The turn stores them with the user message. */
|
|
@@ -39,7 +39,7 @@ export async function assembleMessages(args) {
|
|
|
39
39
|
content: normalizeUnicode(redactSecrets(args.userInput)),
|
|
40
40
|
};
|
|
41
41
|
const contextRecords = await contextRecordsFor(args, history);
|
|
42
|
-
return {
|
|
42
|
+
return { history, userMessage, contextRecords };
|
|
43
43
|
}
|
|
44
44
|
/** The context records of one turn, in the order analysis context, run activity, working memory. */
|
|
45
45
|
export async function contextRecordsFor(args, history) {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Chat-stream events — the harness wire vocabulary.
|
|
3
3
|
*
|
|
4
4
|
* Distinct from the 15 `data-*` chat parts (`chat-parts.ts`): those are UI
|
|
5
5
|
* presentation payloads a tool emits; these are the agent-loop stream events
|
|
6
|
-
* the
|
|
7
|
-
*
|
|
6
|
+
* the host chat route frames as SSE. Together they are the sole
|
|
7
|
+
* host↔frontend wire contract — there is no AI SDK UI Message Stream
|
|
8
8
|
* Protocol and no translation layer.
|
|
9
9
|
*
|
|
10
10
|
* Every event carries `source` — the agent call chain at the point of
|
|
11
11
|
* emission, derived from the harness `Session.callPath`.
|
|
12
12
|
*/
|
|
13
|
+
import type { ChatPart } from "./chat-parts.js";
|
|
13
14
|
import type { TokenUsageRollup } from "./usage.js";
|
|
14
15
|
/**
|
|
15
16
|
* Provenance stamped on every chat-stream event: the emitting agent and the
|
|
@@ -131,5 +132,11 @@ export interface ChatErrorEvent {
|
|
|
131
132
|
reason?: string;
|
|
132
133
|
source: EventSource;
|
|
133
134
|
}
|
|
134
|
-
/** The discriminated union of all
|
|
135
|
-
export type
|
|
135
|
+
/** The discriminated union of all chat-stream events. */
|
|
136
|
+
export type ChatEvent = TextDeltaEvent | ToolStartedEvent | ToolFinishedEvent | FinishEvent | ChatErrorEvent;
|
|
137
|
+
/** A `data-*` part as a frame, with the source of its emitter when the emitter stamped one. */
|
|
138
|
+
export type ChatPartFrame = ChatPart & {
|
|
139
|
+
source?: EventSource;
|
|
140
|
+
};
|
|
141
|
+
/** One frame of a chat stream or a run stream: a loop event or a `data-*` part. */
|
|
142
|
+
export type ChatFrame = ChatEvent | ChatPartFrame;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Chat-stream events — the harness wire vocabulary.
|
|
3
3
|
*
|
|
4
4
|
* Distinct from the 15 `data-*` chat parts (`chat-parts.ts`): those are UI
|
|
5
5
|
* presentation payloads a tool emits; these are the agent-loop stream events
|
|
6
|
-
* the
|
|
7
|
-
*
|
|
6
|
+
* the host chat route frames as SSE. Together they are the sole
|
|
7
|
+
* host↔frontend wire contract — there is no AI SDK UI Message Stream
|
|
8
8
|
* Protocol and no translation layer.
|
|
9
9
|
*
|
|
10
10
|
* Every event carries `source` — the agent call chain at the point of
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ChatDataPart, EmitEvent } from "../loop/types.js";
|
|
2
|
+
import type { ChatStreamEvent } from "../providers/types.js";
|
|
3
|
+
import type { ChatErrorEvent, ChatFrame, ChatPartFrame } from "./chat-events.js";
|
|
4
|
+
import type { ChatMessage, MessagePart } from "./message.js";
|
|
5
|
+
export type TurnTerminal = null | "finish" | {
|
|
6
|
+
error: ChatErrorEvent;
|
|
7
|
+
};
|
|
8
|
+
export interface ApplyFrameResult {
|
|
9
|
+
messages: ChatMessage[];
|
|
10
|
+
terminal: TurnTerminal;
|
|
11
|
+
}
|
|
12
|
+
export type ChatPartCheck = {
|
|
13
|
+
readonly ok: true;
|
|
14
|
+
readonly frame: ChatPartFrame;
|
|
15
|
+
} | {
|
|
16
|
+
readonly ok: false;
|
|
17
|
+
readonly error: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The frame of one emitted event, or `null` for `iteration` and `done`. A frame of a sub-agent keeps its source, thus a
|
|
21
|
+
* consumer can filter it. A `text-delta` has no source, thus its frame gets `fallbackSource`, the source of the root agent.
|
|
22
|
+
* A part frame is not checked here: {@link checkChatPart} checks it where it arrives.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toChatFrame(event: EmitEvent | ChatStreamEvent | ChatDataPart, fallbackSource: EmitEvent["source"]): ChatFrame | null;
|
|
25
|
+
/**
|
|
26
|
+
* Check a part frame against the schema of its type, one time, where it arrives. The schema drops a field that it
|
|
27
|
+
* does not know. A type that the registry does not know passes unchanged, because a newer emitter can send it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkChatPart(frame: ChatPartFrame): ChatPartCheck;
|
|
30
|
+
/** A frame of the root agent of a chat turn, whose call path is `[agent.id]`. A longer path is a sub-agent. */
|
|
31
|
+
export declare function isRootFrame(frame: ChatFrame): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The key that a part reconciles on: a tool call by its call id, and a part of a `reconciling` type by its type and
|
|
34
|
+
* id. A part with no key always appends. The type is part of the key, because an id is unique only in its own type.
|
|
35
|
+
*/
|
|
36
|
+
export declare function reconcileKey(part: MessagePart): string | undefined;
|
|
37
|
+
/** Add a part, or replace the part with the same {@link reconcileKey} in the position of that part. */
|
|
38
|
+
export declare function upsertPart(parts: readonly MessagePart[], part: MessagePart): MessagePart[];
|
|
39
|
+
/** Apply one frame to the messages of a live turn, with no change to the input. A frame of a sub-agent changes nothing. */
|
|
40
|
+
export declare function applyChatFrame(messages: ChatMessage[], frame: ChatFrame, assistantId: string): ApplyFrameResult;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// The one translation path of a chat stream. Browser-safe: each import from outside `contracts/` is a type import.
|
|
2
|
+
import { isReconciling, PART_REGISTRY } from "./part-registry.js";
|
|
3
|
+
import { ChatPartSchema } from "./schemas/chat-parts.js";
|
|
4
|
+
function toSource(source) {
|
|
5
|
+
return { agentId: source.agentId, callPath: [...source.callPath] };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The frame of one emitted event, or `null` for `iteration` and `done`. A frame of a sub-agent keeps its source, thus a
|
|
9
|
+
* consumer can filter it. A `text-delta` has no source, thus its frame gets `fallbackSource`, the source of the root agent.
|
|
10
|
+
* A part frame is not checked here: {@link checkChatPart} checks it where it arrives.
|
|
11
|
+
*/
|
|
12
|
+
export function toChatFrame(event, fallbackSource) {
|
|
13
|
+
switch (event.type) {
|
|
14
|
+
case "iteration":
|
|
15
|
+
case "done":
|
|
16
|
+
return null;
|
|
17
|
+
case "tool-started":
|
|
18
|
+
return {
|
|
19
|
+
type: "tool-started",
|
|
20
|
+
toolUseId: event.toolUseId,
|
|
21
|
+
name: event.name,
|
|
22
|
+
...(event.detail === undefined ? {} : { detail: event.detail }),
|
|
23
|
+
source: toSource(event.source),
|
|
24
|
+
};
|
|
25
|
+
case "tool-finished":
|
|
26
|
+
return {
|
|
27
|
+
type: "tool-finished",
|
|
28
|
+
toolUseId: event.toolUseId,
|
|
29
|
+
name: event.name,
|
|
30
|
+
outcome: event.outcome,
|
|
31
|
+
...(event.detail === undefined ? {} : { detail: event.detail }),
|
|
32
|
+
...(event.durationMs === undefined ? {} : { durationMs: event.durationMs }),
|
|
33
|
+
source: toSource(event.source),
|
|
34
|
+
};
|
|
35
|
+
case "text-delta":
|
|
36
|
+
return { type: "text-delta", text: event.text, source: toSource(fallbackSource) };
|
|
37
|
+
default: {
|
|
38
|
+
// A `ChatDataPart`, whose payload the emitter types as `unknown`. The wire part is flat: `{ type, ...data }`.
|
|
39
|
+
// The cast names the frame that the type claims. `checkChatPart` is the check.
|
|
40
|
+
const data = (event.data ?? {});
|
|
41
|
+
return { ...data, type: event.type, ...(event.source === undefined ? {} : { source: toSource(event.source) }) };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check a part frame against the schema of its type, one time, where it arrives. The schema drops a field that it
|
|
47
|
+
* does not know. A type that the registry does not know passes unchanged, because a newer emitter can send it.
|
|
48
|
+
*/
|
|
49
|
+
export function checkChatPart(frame) {
|
|
50
|
+
if (!Object.hasOwn(PART_REGISTRY, frame.type))
|
|
51
|
+
return { ok: true, frame };
|
|
52
|
+
const { source, ...part } = frame;
|
|
53
|
+
const parsed = ChatPartSchema.safeParse(part);
|
|
54
|
+
if (!parsed.success)
|
|
55
|
+
return { ok: false, error: parsed.error.message };
|
|
56
|
+
return { ok: true, frame: source === undefined ? parsed.data : { ...parsed.data, source } };
|
|
57
|
+
}
|
|
58
|
+
/** A frame of the root agent of a chat turn, whose call path is `[agent.id]`. A longer path is a sub-agent. */
|
|
59
|
+
export function isRootFrame(frame) {
|
|
60
|
+
return frame.source === undefined || frame.source.callPath.length <= 1;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The key that a part reconciles on: a tool call by its call id, and a part of a `reconciling` type by its type and
|
|
64
|
+
* id. A part with no key always appends. The type is part of the key, because an id is unique only in its own type.
|
|
65
|
+
*/
|
|
66
|
+
export function reconcileKey(part) {
|
|
67
|
+
if (part.type === "tool-call")
|
|
68
|
+
return `tool-call:${part.toolCallId}`;
|
|
69
|
+
if (part.type === "text" || !Object.hasOwn(PART_REGISTRY, part.type) || !isReconciling(part.type))
|
|
70
|
+
return undefined;
|
|
71
|
+
return "id" in part && typeof part.id === "string" ? `${part.type}:${part.id}` : undefined;
|
|
72
|
+
}
|
|
73
|
+
/** Add a part, or replace the part with the same {@link reconcileKey} in the position of that part. */
|
|
74
|
+
export function upsertPart(parts, part) {
|
|
75
|
+
const key = reconcileKey(part);
|
|
76
|
+
const index = key === undefined ? -1 : parts.findIndex((candidate) => reconcileKey(candidate) === key);
|
|
77
|
+
if (index === -1)
|
|
78
|
+
return [...parts, part];
|
|
79
|
+
const next = parts.slice();
|
|
80
|
+
next[index] = part;
|
|
81
|
+
return next;
|
|
82
|
+
}
|
|
83
|
+
/** Apply one frame to the messages of a live turn, with no change to the input. A frame of a sub-agent changes nothing. */
|
|
84
|
+
export function applyChatFrame(messages, frame, assistantId) {
|
|
85
|
+
if (!isRootFrame(frame))
|
|
86
|
+
return { messages, terminal: null };
|
|
87
|
+
if (frame.type === "finish") {
|
|
88
|
+
return {
|
|
89
|
+
messages: frame.turnUsage === undefined ? messages : stampUsage(messages, assistantId, frame.turnUsage),
|
|
90
|
+
terminal: "finish",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (frame.type === "error") {
|
|
94
|
+
return { messages, terminal: { error: frame } };
|
|
95
|
+
}
|
|
96
|
+
const partFrame = frame;
|
|
97
|
+
const next = updateAssistant(messages, assistantId, (parts) => applyPartFrame(parts, partFrame));
|
|
98
|
+
return { messages: next, terminal: null };
|
|
99
|
+
}
|
|
100
|
+
function applyPartFrame(parts, frame) {
|
|
101
|
+
switch (frame.type) {
|
|
102
|
+
case "text-delta":
|
|
103
|
+
return mergeTextDelta(parts, frame.text);
|
|
104
|
+
case "tool-started":
|
|
105
|
+
return [
|
|
106
|
+
...parts,
|
|
107
|
+
{
|
|
108
|
+
type: "tool-call",
|
|
109
|
+
toolCallId: frame.toolUseId,
|
|
110
|
+
toolName: frame.name,
|
|
111
|
+
...(frame.detail === undefined ? {} : { detail: frame.detail }),
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
case "tool-finished": {
|
|
115
|
+
const finished = {
|
|
116
|
+
type: "tool-call",
|
|
117
|
+
toolCallId: frame.toolUseId,
|
|
118
|
+
toolName: frame.name,
|
|
119
|
+
outcome: frame.outcome,
|
|
120
|
+
...(frame.detail === undefined ? {} : { detail: frame.detail }),
|
|
121
|
+
...(frame.durationMs === undefined ? {} : { durationMs: frame.durationMs }),
|
|
122
|
+
};
|
|
123
|
+
let started = false;
|
|
124
|
+
const next = parts.map((p) => {
|
|
125
|
+
if (p.type !== "tool-call" || p.toolCallId !== frame.toolUseId)
|
|
126
|
+
return p;
|
|
127
|
+
started = true;
|
|
128
|
+
return { ...p, ...finished };
|
|
129
|
+
});
|
|
130
|
+
// The stored transcript keeps a call whose start never arrived, thus a live view keeps it too.
|
|
131
|
+
return started ? next : [...parts, finished];
|
|
132
|
+
}
|
|
133
|
+
default: {
|
|
134
|
+
// The source routes the frame, and it is not a field of the part. A rest type does not distribute over the
|
|
135
|
+
// union of the part frames, thus the cast names the part that remains.
|
|
136
|
+
const { source: _source, ...part } = frame;
|
|
137
|
+
return upsertPart(parts, part);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function mergeTextDelta(parts, delta) {
|
|
142
|
+
const last = parts[parts.length - 1];
|
|
143
|
+
if (last && last.type === "text") {
|
|
144
|
+
const merged = { type: "text", text: last.text + delta };
|
|
145
|
+
return [...parts.slice(0, -1), merged];
|
|
146
|
+
}
|
|
147
|
+
return [...parts, { type: "text", text: delta }];
|
|
148
|
+
}
|
|
149
|
+
function stampUsage(messages, assistantId, usage) {
|
|
150
|
+
const idx = messages.findIndex((m) => m.id === assistantId);
|
|
151
|
+
const message = messages[idx];
|
|
152
|
+
if (message === undefined)
|
|
153
|
+
return messages;
|
|
154
|
+
const next = messages.slice();
|
|
155
|
+
next[idx] = { ...message, usage };
|
|
156
|
+
return next;
|
|
157
|
+
}
|
|
158
|
+
function updateAssistant(messages, assistantId, updater) {
|
|
159
|
+
const idx = messages.findIndex((m) => m.id === assistantId);
|
|
160
|
+
const existing = messages[idx];
|
|
161
|
+
if (existing === undefined)
|
|
162
|
+
return [...messages, { id: assistantId, role: "assistant", parts: updater([]) }];
|
|
163
|
+
const next = messages.slice();
|
|
164
|
+
next[idx] = { ...existing, parts: updater(existing.parts) };
|
|
165
|
+
return next;
|
|
166
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Chat data parts — the `data-*` parts that a tool or a workflow emits, and that
|
|
3
|
+
* a surface renders from the chat stream or the run stream.
|
|
4
4
|
*
|
|
5
5
|
* Categories:
|
|
6
6
|
* Presentation: data-presentation (agent-synthesized content),
|
|
@@ -22,8 +22,16 @@ export interface PlanStep {
|
|
|
22
22
|
resources?: {
|
|
23
23
|
cpu: number;
|
|
24
24
|
memoryGb: number;
|
|
25
|
+
gpu?: {
|
|
26
|
+
count: number;
|
|
27
|
+
};
|
|
25
28
|
};
|
|
26
29
|
maxSteps: number;
|
|
30
|
+
track?: string;
|
|
31
|
+
step_type?: string;
|
|
32
|
+
acceptance_criteria?: string[];
|
|
33
|
+
constraints?: string[];
|
|
34
|
+
caveats?: string[];
|
|
27
35
|
}
|
|
28
36
|
export type PresentationContent =
|
|
29
37
|
/** `dataPath` (optional): an analysis-rooted CSV artifact path the host loads and injects as the
|
|
@@ -388,8 +396,12 @@ export interface CompactionPart {
|
|
|
388
396
|
type: "data-compaction";
|
|
389
397
|
id: string;
|
|
390
398
|
status: "running" | "done" | "failed";
|
|
399
|
+
/** The input tokens that the provider reported for the last request before the compaction. */
|
|
391
400
|
tokensBefore: number;
|
|
401
|
+
/** Only a part that an older harness stored carries it: an estimate of the view after the compaction. */
|
|
392
402
|
tokensAfter?: number;
|
|
393
403
|
durationMs?: number;
|
|
404
|
+
/** Before the user message of a turn, or before a later request. */
|
|
405
|
+
trigger?: "turn-start" | "mid-turn";
|
|
394
406
|
}
|
|
395
|
-
export type
|
|
407
|
+
export type ChatPart = PresentationPart | PlanPart | RunCardPart | FileReferencePart | AskPart | RunStartedPart | DagStatePart | StepActivityPart | StepFileTreePart | StepOutputPart | StepSummaryPart | StepUsagePart | StepBlockedPart | RunSynthesisPart | SynthesisProgressPart | RunCompletedPart | RunFailedPart | ChildSessionStartedPart | ReportRenderedPart | CompactionPart;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Chat data parts — the `data-*` parts that a tool or a workflow emits, and that
|
|
3
|
+
* a surface renders from the chat stream or the run stream.
|
|
4
4
|
*
|
|
5
5
|
* Categories:
|
|
6
6
|
* Presentation: data-presentation (agent-synthesized content),
|
|
@@ -2,16 +2,18 @@ export { ORGAN_SYSTEMS, OrganSystemSchema, ORGAN_SYSTEM_LABELS, organSystemLabel
|
|
|
2
2
|
export type { OrganSystem } from "./organ-system.js";
|
|
3
3
|
export { SEVERITIES, SeveritySchema } from "./severity.js";
|
|
4
4
|
export type { Severity } from "./severity.js";
|
|
5
|
-
export type { PlanStep, PresentationContent, PresentationPart, PlanPart, RunCardPart, FileReferenceEntry, FileReferencePart, AskPart, RunStartedPart, StepStatus, DagStepState, DagStatePart, StepPhase, StepActivityPart, FileTreeEntry, StepFileTreePart, StepOutputFile, StepOutputPart, StepSummaryPart, StepUsagePart, StepBlockedPart, SynthesizedFinding, BiologicalTheme, RunSynthesisPart, SynthesisPhase, SynthesisProgressPart, RunCompletedFinding, RunCompletedPart, RunFailedPart, ChildSessionStartedPart, ReportRenderedPart, CompactionPart,
|
|
6
|
-
export type { EventSource, TextDeltaEvent, ToolStartedEvent, ToolFinishedEvent, FinishEvent, ChatErrorEvent,
|
|
5
|
+
export type { PlanStep, PresentationContent, PresentationPart, PlanPart, RunCardPart, FileReferenceEntry, FileReferencePart, AskPart, RunStartedPart, StepStatus, DagStepState, DagStatePart, StepPhase, StepActivityPart, FileTreeEntry, StepFileTreePart, StepOutputFile, StepOutputPart, StepSummaryPart, StepUsagePart, StepBlockedPart, SynthesizedFinding, BiologicalTheme, RunSynthesisPart, SynthesisPhase, SynthesisProgressPart, RunCompletedFinding, RunCompletedPart, RunFailedPart, ChildSessionStartedPart, ReportRenderedPart, CompactionPart, ChatPart, } from "./chat-parts.js";
|
|
6
|
+
export type { EventSource, TextDeltaEvent, ToolStartedEvent, ToolFinishedEvent, FinishEvent, ChatErrorEvent, ChatEvent, ChatFrame, ChatPartFrame, } from "./chat-events.js";
|
|
7
7
|
export type { TokenUsageRollup } from "./usage.js";
|
|
8
8
|
export { DATA_PROFILE_RUN_LITERAL } from "./data-profile.js";
|
|
9
9
|
export type { DataProfileAxis, DataProfileChecked, DataProfileCompanionCompleteness, DataProfileCoverage, DataProfileDimension, DataProfileFile, DataProfileGroup, DataProfileGroupSlot, DataProfileInputSignature, DataProfileKind, DataProfileLifecycleStatus, DataProfileMemberAnnotation, DataProfileObservation, DataProfileOrganism, DataProfilePartition, DataProfileProbeReport, DataProfileQualityAssessment, DataProfileQuarantine, DataProfileRecipeStep, DataProfileResult, DataProfileSubjectSource, } from "./data-profile.js";
|
|
10
10
|
export { DIMENSION_CATEGORIES, DIMENSION_CATEGORY_IDS, DIMENSION_PROBE_IDS, DIMENSION_PROBES, GROUP_CATEGORIES, GROUP_CATEGORY_IDS, GROUP_ROLE_IDS, GROUP_ROLES, PROBE_OUTCOME_IDS, dimensionCategoryEntry, dimensionScope, groupCategoryEntry, } from "./profile-vocabulary.js";
|
|
11
11
|
export type { DimensionCategory, DimensionCategoryEntry, DimensionProbe, DimensionProbeEntry, DimensionScope, DimensionTreatment, GroupCategory, GroupCategoryEntry, GroupRole, GroupRoleEntry, ProbeOutcome, } from "./profile-vocabulary.js";
|
|
12
|
-
export type { TextPart, ToolCallPart,
|
|
12
|
+
export type { TextPart, ToolCallPart, MessagePart, ChatMessage } from "./message.js";
|
|
13
|
+
export { toChatFrame, applyChatFrame, checkChatPart } from "./chat-frame.js";
|
|
14
|
+
export type { TurnTerminal, ApplyFrameResult, ChatPartCheck } from "./chat-frame.js";
|
|
13
15
|
export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./part-registry.js";
|
|
14
|
-
export type {
|
|
16
|
+
export type { ChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./part-registry.js";
|
|
15
17
|
export { AnalogyCoverageSchema, AnalogyReportSchema, AnalogyReportErrorSchema, AnalogicalReasonerOutputSchema } from "./analogy-report.js";
|
|
16
18
|
export type { AnalogyCoverage, AnalogyReport, AnalogyReportError, AnalogicalReasonerOutput } from "./analogy-report.js";
|
|
17
19
|
export { buildReportSessionUrl, reportSessionResourceId } from "./content-url.js";
|
package/dist/contracts/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export { ORGAN_SYSTEMS, OrganSystemSchema, ORGAN_SYSTEM_LABELS, organSystemLabel
|
|
|
2
2
|
export { SEVERITIES, SeveritySchema } from "./severity.js";
|
|
3
3
|
export { DATA_PROFILE_RUN_LITERAL } from "./data-profile.js";
|
|
4
4
|
export { DIMENSION_CATEGORIES, DIMENSION_CATEGORY_IDS, DIMENSION_PROBE_IDS, DIMENSION_PROBES, GROUP_CATEGORIES, GROUP_CATEGORY_IDS, GROUP_ROLE_IDS, GROUP_ROLES, PROBE_OUTCOME_IDS, dimensionCategoryEntry, dimensionScope, groupCategoryEntry, } from "./profile-vocabulary.js";
|
|
5
|
+
export { toChatFrame, applyChatFrame, checkChatPart } from "./chat-frame.js";
|
|
5
6
|
export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./part-registry.js";
|
|
6
7
|
export { AnalogyCoverageSchema, AnalogyReportSchema, AnalogyReportErrorSchema, AnalogicalReasonerOutputSchema } from "./analogy-report.js";
|
|
7
8
|
export { buildReportSessionUrl, reportSessionResourceId } from "./content-url.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Chat message types — the wire shape, the in-memory shape,
|
|
3
3
|
* and the public API for everything the chat path exchanges.
|
|
4
4
|
*
|
|
5
5
|
* No AI SDK types appear here or anywhere else in the package. The
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* narrows the union member without any `as` cast.
|
|
8
8
|
*/
|
|
9
9
|
import type { ToolCallDetail, ToolCallOutcome } from "./chat-events.js";
|
|
10
|
-
import type {
|
|
10
|
+
import type { ChatPart } from "./chat-parts.js";
|
|
11
11
|
import type { TokenUsageRollup } from "./usage.js";
|
|
12
12
|
/** A plain assistant/user text run. */
|
|
13
13
|
export interface TextPart {
|
|
@@ -38,14 +38,16 @@ export interface ToolCallPart {
|
|
|
38
38
|
outcome?: ToolCallOutcome;
|
|
39
39
|
/** See {@link ToolCallDetail}. Absent when no detail was produced. */
|
|
40
40
|
detail?: ToolCallDetail;
|
|
41
|
+
/** The time in milliseconds around the dispatch of the call, from `tool-finished`. Absent when no measurement was taken. */
|
|
42
|
+
durationMs?: number;
|
|
41
43
|
}
|
|
42
44
|
/** The discriminated union of every part the chat path can carry. */
|
|
43
|
-
export type
|
|
45
|
+
export type MessagePart = TextPart | ToolCallPart | ChatPart;
|
|
44
46
|
/** A single chat message — user, assistant, or system. */
|
|
45
|
-
export interface
|
|
47
|
+
export interface ChatMessage {
|
|
46
48
|
id: string;
|
|
47
49
|
role: "user" | "assistant" | "system";
|
|
48
|
-
parts:
|
|
50
|
+
parts: MessagePart[];
|
|
49
51
|
/**
|
|
50
52
|
* Set when this message's production was cut off by a client abort, so the UI
|
|
51
53
|
* can badge it. Absent means not interrupted — the field is optional so every
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Chat message types — the wire shape, the in-memory shape,
|
|
3
3
|
* and the public API for everything the chat path exchanges.
|
|
4
4
|
*
|
|
5
5
|
* No AI SDK types appear here or anywhere else in the package. The
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type
|
|
1
|
+
import type { ChatPart } from "./chat-parts.js";
|
|
2
|
+
export type ChatPartType = ChatPart["type"];
|
|
3
3
|
export type PartEmitter = "workflow" | "conversation";
|
|
4
4
|
export type PartConsumer = "sidebar" | "conversation";
|
|
5
5
|
export interface PartDescriptor {
|
|
@@ -12,7 +12,7 @@ export interface PartDescriptor {
|
|
|
12
12
|
/** If true, multiple emissions share the same id — latest wins. */
|
|
13
13
|
reconciling: boolean;
|
|
14
14
|
}
|
|
15
|
-
export declare const PART_REGISTRY: Record<
|
|
16
|
-
export declare function isTransient(type:
|
|
17
|
-
export declare function isReconciling(type:
|
|
18
|
-
export declare function isSidebarPart(type:
|
|
15
|
+
export declare const PART_REGISTRY: Record<ChatPartType, PartDescriptor>;
|
|
16
|
+
export declare function isTransient(type: ChatPartType): boolean;
|
|
17
|
+
export declare function isReconciling(type: ChatPartType): boolean;
|
|
18
|
+
export declare function isSidebarPart(type: ChatPartType): boolean;
|