@inflexa-ai/harness 0.14.1 → 0.15.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/README.md +2 -1
- package/dist/agents/conversation-agent.d.ts +7 -0
- package/dist/agents/conversation-agent.js +5 -3
- package/dist/app/synthesize-run.d.ts +3 -0
- package/dist/app/synthesize-run.js +2 -1
- package/dist/billing/noop-usage-recorder.d.ts +7 -0
- package/dist/billing/noop-usage-recorder.js +10 -0
- package/dist/billing/usage-recorder.d.ts +63 -0
- package/dist/billing/usage-recorder.js +15 -0
- package/dist/contracts/chat-events.d.ts +44 -3
- package/dist/contracts/chat-parts.d.ts +38 -2
- package/dist/contracts/chat-parts.js +1 -1
- package/dist/contracts/data-profile.d.ts +26 -0
- package/dist/contracts/data-profile.js +26 -0
- package/dist/contracts/index.d.ts +3 -1
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/message.d.ts +21 -1
- package/dist/contracts/part-registry.js +1 -0
- package/dist/contracts/schemas/chat-events.d.ts +48 -2
- package/dist/contracts/schemas/chat-events.js +8 -1
- package/dist/contracts/schemas/chat-parts.d.ts +46 -3
- package/dist/contracts/schemas/chat-parts.js +13 -0
- package/dist/contracts/schemas/index.d.ts +2 -1
- package/dist/contracts/schemas/index.js +2 -1
- package/dist/contracts/schemas/usage.d.ts +11 -0
- package/dist/contracts/schemas/usage.js +18 -0
- package/dist/contracts/usage.d.ts +51 -0
- package/dist/contracts/usage.js +41 -0
- package/dist/execution/artifact-metadata.d.ts +3 -0
- package/dist/execution/artifact-metadata.js +1 -0
- package/dist/execution/dbos-workflow-purger.d.ts +30 -0
- package/dist/execution/dbos-workflow-purger.js +193 -0
- package/dist/execution/post-step-pipeline.d.ts +3 -0
- package/dist/execution/post-step-pipeline.js +2 -0
- package/dist/execution/reconcile-manifest.js +28 -15
- package/dist/execution/report-runner.d.ts +16 -0
- package/dist/execution/report-runner.js +4 -0
- package/dist/execution/run-synthesis.d.ts +3 -0
- package/dist/execution/run-synthesis.js +2 -0
- package/dist/execution/step-summary.d.ts +3 -0
- package/dist/execution/step-summary.js +1 -0
- package/dist/execution/workflow-purger.d.ts +38 -0
- package/dist/execution/workflow-purger.js +24 -0
- package/dist/index.d.ts +25 -3
- package/dist/index.js +28 -1
- package/dist/lib/metrics.js +2 -1
- package/dist/loop/metrics.d.ts +18 -0
- package/dist/loop/metrics.js +18 -1
- package/dist/loop/run-agent.d.ts +35 -0
- package/dist/loop/run-agent.js +149 -23
- package/dist/loop/run-to-terminal.d.ts +5 -2
- package/dist/loop/run-to-terminal.js +36 -2
- package/dist/loop/tool-detail.d.ts +54 -0
- package/dist/loop/tool-detail.js +105 -0
- package/dist/loop/tool-outcome.d.ts +21 -0
- package/dist/loop/tool-outcome.js +25 -0
- package/dist/loop/types.d.ts +15 -1
- package/dist/memory/content-to-cortex.d.ts +28 -4
- package/dist/memory/content-to-cortex.js +70 -14
- package/dist/memory/thread-history.d.ts +21 -1
- package/dist/memory/thread-history.js +29 -7
- package/dist/memory/thread-store.d.ts +65 -8
- package/dist/memory/thread-store.js +81 -17
- package/dist/provenance/collector.d.ts +5 -3
- package/dist/provenance/collector.js +5 -3
- package/dist/providers/ai-sdk.d.ts +18 -0
- package/dist/providers/ai-sdk.js +129 -16
- package/dist/providers/anthropic.d.ts +2 -0
- package/dist/providers/anthropic.js +1 -0
- package/dist/providers/streaming-chat.js +5 -0
- package/dist/providers/types.d.ts +23 -0
- package/dist/providers/types.js +1 -0
- package/dist/runtime/assemble.d.ts +25 -8
- package/dist/runtime/assemble.js +7 -4
- package/dist/sandbox/sandbox-step-translate.d.ts +22 -1
- package/dist/sandbox/sandbox-step-translate.js +23 -36
- package/dist/schemas/run-synthesis.d.ts +2 -2
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.js +3 -0
- package/dist/state/init.js +28 -0
- package/dist/state/purge-analysis.d.ts +74 -0
- package/dist/state/purge-analysis.js +205 -0
- package/dist/state/vector-store.d.ts +6 -0
- package/dist/state/vector-store.js +22 -2
- package/dist/tasks/data-profile-activity.d.ts +14 -2
- package/dist/tasks/data-profile-activity.js +1 -1
- package/dist/tasks/data-profile.d.ts +3 -0
- package/dist/tasks/data-profile.js +9 -3
- package/dist/tools/bio/pubmed.js +15 -0
- package/dist/tools/bio/search-gene.js +12 -0
- package/dist/tools/define-tool.d.ts +41 -3
- package/dist/tools/define-tool.js +4 -1
- package/dist/tools/detail-resolver.d.ts +35 -0
- package/dist/tools/detail-resolver.js +39 -0
- package/dist/tools/execute-analysis.js +3 -0
- package/dist/tools/iterate-report.d.ts +3 -0
- package/dist/tools/iterate-report.js +3 -0
- package/dist/tools/memory/update-working-memory.js +8 -0
- package/dist/tools/research/generate-analogy-report.d.ts +3 -0
- package/dist/tools/research/generate-analogy-report.js +6 -0
- package/dist/tools/research/generate-plan.d.ts +3 -0
- package/dist/tools/research/generate-plan.js +6 -0
- package/dist/tools/research/inspect-run.js +4 -0
- package/dist/tools/research/literature-reviewer.d.ts +3 -0
- package/dist/tools/research/literature-reviewer.js +6 -0
- package/dist/tools/workspace/edit-file.js +2 -0
- package/dist/tools/workspace/execute-command.js +25 -0
- package/dist/tools/workspace/grep.js +3 -0
- package/dist/tools/workspace/list-files.js +2 -0
- package/dist/tools/workspace/read-file.js +7 -0
- package/dist/tools/workspace/workspace-search.js +1 -0
- package/dist/tools/workspace/write-file.js +3 -0
- package/dist/workflows/execute-analysis.d.ts +7 -0
- package/dist/workflows/execute-analysis.js +31 -2
- package/dist/workflows/execute-target-assessment.d.ts +3 -0
- package/dist/workflows/sandbox-step.d.ts +23 -0
- package/dist/workflows/sandbox-step.js +33 -2
- package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.d.ts +3 -0
- package/dist/workflows/target-assessment/lib/clinical-consequence-annotator.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
createLocalRunAuthorizer, // RunAuthorizer seam (local default)
|
|
35
35
|
createNoopBillingResolver, // ResolveBilling seam
|
|
36
36
|
createNoopRunCharge, // RunCharge seam
|
|
37
|
+
createNoopUsageRecorder, // UsageRecorder seam
|
|
37
38
|
createNoopArtifactRegistry, // ArtifactRegistry seam
|
|
38
39
|
UnavailablePreviewPublisher, // PreviewPublisher seam
|
|
39
40
|
createDbosRunLauncher, // shared RunLauncher
|
|
@@ -46,7 +47,7 @@ import {
|
|
|
46
47
|
} from "@inflexa-ai/harness";
|
|
47
48
|
```
|
|
48
49
|
|
|
49
|
-
`assembleCoreRuntime` is the single composition point: it registers the durable workflows and builds the conversation agent over them. The harness declares **
|
|
50
|
+
`assembleCoreRuntime` is the single composition point: it registers the durable workflows and builds the conversation agent over them. The harness declares **six capability seams** an embedder wires — `RunAuthorizer`, `ResolveBilling`, `ArtifactRegistry`, `RunCharge`, `UsageRecorder`, `PreviewPublisher` — plus the **shared `RunLauncher`** (one host-neutral realization, `createDbosRunLauncher`). Local, dependency-free realizations of all six ship from the barrel; an embedder constructs them (or its own) and passes them in. The harness only ever sees the interface.
|
|
50
51
|
|
|
51
52
|
## Logging
|
|
52
53
|
|
|
@@ -40,6 +40,7 @@ import type { RunAuthorizer } from "../execution/run-authorizer.js";
|
|
|
40
40
|
import type { RunLauncher } from "../execution/run-launcher.js";
|
|
41
41
|
import { type SubmitReportDeps } from "../tools/iterate-report.js";
|
|
42
42
|
import type { Logger } from "../lib/logger.js";
|
|
43
|
+
import type { UsageRecorder } from "../billing/usage-recorder.js";
|
|
43
44
|
/** Canonical agent id — the single source of truth. */
|
|
44
45
|
export declare const CONVERSATION_AGENT_ID: "conversation-agent";
|
|
45
46
|
/**
|
|
@@ -51,6 +52,12 @@ export declare const CONVERSATION_AGENT_ID: "conversation-agent";
|
|
|
51
52
|
export interface ConversationAgentDeps extends EnvironmentStorePaths {
|
|
52
53
|
/** Operational logging seam; omitted falls back to no-op. */
|
|
53
54
|
readonly logger?: Logger;
|
|
55
|
+
/**
|
|
56
|
+
* LLM usage-accounting seam, handed to every loop-driving tool this agent
|
|
57
|
+
* owns so a sub-agent's calls land in the same ledger as the turn's.
|
|
58
|
+
* Omitted falls back to the no-op recorder.
|
|
59
|
+
*/
|
|
60
|
+
readonly usageRecorder?: UsageRecorder;
|
|
54
61
|
/** The LLM seam every loop-driving tool runs its sub-agent on. */
|
|
55
62
|
readonly provider: ChatProvider;
|
|
56
63
|
/** Postgres pool — plan persistence, run inspection, workspace index, working memory. */
|
|
@@ -46,7 +46,7 @@ export const CONVERSATION_AGENT_ID = "conversation-agent";
|
|
|
46
46
|
const CONVERSATION_MAX_ITERATIONS = 50;
|
|
47
47
|
/** Build the conversation `AgentDefinition` with every tool fully dep-bound. */
|
|
48
48
|
export function createConversationAgent(deps) {
|
|
49
|
-
const { provider, pool, embedding, workspaceFs, model, utilityProvider, utilityModel, executeAnalysisWorkflow, resolveWorkspaceRoot, runAuthorizer, runLauncher, createPreviewPublisher, bioKeys, templatesDir, skillsDir, chrome, resourcePolicy, hostTools, refStorePath, packagesFile, } = deps;
|
|
49
|
+
const { provider, pool, embedding, workspaceFs, model, utilityProvider, utilityModel, executeAnalysisWorkflow, resolveWorkspaceRoot, runAuthorizer, runLauncher, createPreviewPublisher, bioKeys, templatesDir, skillsDir, chrome, resourcePolicy, hostTools, refStorePath, packagesFile, usageRecorder, } = deps;
|
|
50
50
|
const workingMemory = createWorkingMemory(pool);
|
|
51
51
|
const ncbi = createNcbiTools(bioKeys);
|
|
52
52
|
const chemDb = createChemDbTools(bioKeys, { ...(deps.logger ? { logger: deps.logger } : {}) });
|
|
@@ -96,6 +96,7 @@ export function createConversationAgent(deps) {
|
|
|
96
96
|
conversation: { provider, model },
|
|
97
97
|
pool,
|
|
98
98
|
resourcePolicy,
|
|
99
|
+
usageRecorder,
|
|
99
100
|
...(refStorePath ? { refStorePath } : {}),
|
|
100
101
|
...(packagesFile ? { packagesFile } : {}),
|
|
101
102
|
...(deps.logger ? { logger: deps.logger } : {}),
|
|
@@ -124,15 +125,16 @@ export function createConversationAgent(deps) {
|
|
|
124
125
|
skillsDir,
|
|
125
126
|
chrome,
|
|
126
127
|
createPreviewPublisher,
|
|
128
|
+
usageRecorder,
|
|
127
129
|
}),
|
|
128
130
|
// Display.
|
|
129
131
|
showUserTool,
|
|
130
132
|
createShowPlanTool(pool),
|
|
131
133
|
showFileTool,
|
|
132
134
|
// Batch literature/biology research (sub-agent as a loop-driving tool).
|
|
133
|
-
createLiteratureReviewerTool({ provider, model, bioKeys }),
|
|
135
|
+
createLiteratureReviewerTool({ provider, model, bioKeys, usageRecorder }),
|
|
134
136
|
// Cross-domain analogy generation (sub-agent as a loop-driving tool).
|
|
135
|
-
createGenerateAnalogyReportTool({ provider, model, bioKeys }),
|
|
137
|
+
createGenerateAnalogyReportTool({ provider, model, bioKeys, usageRecorder }),
|
|
136
138
|
// Workspace semantic search + raw read/grep over the read seam.
|
|
137
139
|
createWorkspaceSearchTool(pool, embedding),
|
|
138
140
|
createReadFileTool(workspaceFs),
|
|
@@ -24,6 +24,7 @@ import type { RunFinding } from "../workflows/execute-analysis.js";
|
|
|
24
24
|
import type { ResolveWorkspaceRoot } from "../workspace/paths.js";
|
|
25
25
|
import type { SynthesisStatus } from "../state/index.js";
|
|
26
26
|
import type { Logger } from "../lib/logger.js";
|
|
27
|
+
import type { UsageRecorder } from "../billing/usage-recorder.js";
|
|
27
28
|
export interface SynthesizeRunDeps {
|
|
28
29
|
/** Operational logging seam; omitted falls back to no-op. */
|
|
29
30
|
readonly logger?: Logger;
|
|
@@ -37,6 +38,8 @@ export interface SynthesizeRunDeps {
|
|
|
37
38
|
readonly synthesisModel: string;
|
|
38
39
|
/** API keys for the bio/chem tools the embedded literature reviewer uses. */
|
|
39
40
|
readonly bioKeys: BioToolKeys;
|
|
41
|
+
/** LLM usage-accounting seam for the synthesizer loop; omitted falls back to the no-op recorder. */
|
|
42
|
+
readonly usageRecorder?: UsageRecorder;
|
|
40
43
|
}
|
|
41
44
|
/** Optional fields for a progress update, mirroring the wire part. */
|
|
42
45
|
export interface SynthesisProgressExtra {
|
|
@@ -22,7 +22,7 @@ import { loadPlan, queryRun } from "../state/index.js";
|
|
|
22
22
|
import { unwrapOrThrow } from "../lib/result.js";
|
|
23
23
|
import { createNoopLogger } from "../lib/console-logger.js";
|
|
24
24
|
export async function synthesizeRun(deps, params) {
|
|
25
|
-
const { pool, provider, embedding, resolveWorkspaceRoot, synthesisModel, bioKeys } = deps;
|
|
25
|
+
const { pool, provider, embedding, resolveWorkspaceRoot, synthesisModel, bioKeys, usageRecorder } = deps;
|
|
26
26
|
const { analysisId, runId, completedSteps, session, emit, onProgress } = params;
|
|
27
27
|
await onProgress("starting", "Beginning literature-grounded synthesis");
|
|
28
28
|
try {
|
|
@@ -47,6 +47,7 @@ export async function synthesizeRun(deps, params) {
|
|
|
47
47
|
session: synthesizerSession,
|
|
48
48
|
model: synthesisModel,
|
|
49
49
|
bioKeys,
|
|
50
|
+
usageRecorder,
|
|
50
51
|
summaries,
|
|
51
52
|
planNarrative,
|
|
52
53
|
runId,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { UsageRecorder } from "./usage-recorder.js";
|
|
2
|
+
/**
|
|
3
|
+
* Local/OSS usage recorder: drops every record. No ledger, no I/O — the
|
|
4
|
+
* default an embedder that wires nothing gets. Runs behave exactly as they did
|
|
5
|
+
* before the seam existed.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createNoopUsageRecorder(): UsageRecorder;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local/OSS usage recorder: drops every record. No ledger, no I/O — the
|
|
3
|
+
* default an embedder that wires nothing gets. Runs behave exactly as they did
|
|
4
|
+
* before the seam existed.
|
|
5
|
+
*/
|
|
6
|
+
export function createNoopUsageRecorder() {
|
|
7
|
+
return {
|
|
8
|
+
record: () => { },
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `UsageRecorder` — the per-call LLM usage-accounting seam.
|
|
3
|
+
*
|
|
4
|
+
* Sibling of `ResolveBilling` and `RunCharge`, and complementary to both:
|
|
5
|
+
* `ResolveBilling` stamps attribution onto a wire call, `RunCharge` brackets a
|
|
6
|
+
* run for managed billing, and `UsageRecorder` streams the fine-grained token
|
|
7
|
+
* telemetry every completed LLM call produces. The harness names no storage or
|
|
8
|
+
* display technology — it emits records; the embedder decides where they land.
|
|
9
|
+
*
|
|
10
|
+
* The loop is the single delivery site (it sees every reply in both execution
|
|
11
|
+
* modes and already holds the session), so a realization is wired once at the
|
|
12
|
+
* composition root and reaches every `runAgent` invocation through the deps
|
|
13
|
+
* bags. OSS default: `createNoopUsageRecorder` (`./noop-usage-recorder.ts`).
|
|
14
|
+
*/
|
|
15
|
+
import type { Scope } from "../auth/types.js";
|
|
16
|
+
import type { ChatUsage } from "../providers/types.js";
|
|
17
|
+
/** One completed LLM call's token usage, with the attribution held at the call site. */
|
|
18
|
+
export interface LlmUsageRecord {
|
|
19
|
+
/**
|
|
20
|
+
* Idempotency key. Stable across every replay of the same call: under a
|
|
21
|
+
* `RunFrame` it composes the `runId`, the frame's `stepId` when it carries
|
|
22
|
+
* one, the session's provenance call path, the dispatching tool call's id
|
|
23
|
+
* when the loop runs nested inside one, and the loop's deterministic step
|
|
24
|
+
* name; outside a `RunFrame` (the chat path, where no replay exists) it is
|
|
25
|
+
* freshly minted. Every component past the frame is load-bearing, because
|
|
26
|
+
* a step name is unique only within one loop invocation and loops routinely
|
|
27
|
+
* share a frame: the `stepId` keeps sibling step workflows of one run
|
|
28
|
+
* apart, the call path keeps distinct agent chains under one frame apart,
|
|
29
|
+
* and the invocation id keeps parallel dispatches of one sub-agent apart.
|
|
30
|
+
* The harness guarantees key stability, not at-most-once delivery —
|
|
31
|
+
* consumers MUST upsert on this key, or a replayed workflow body will
|
|
32
|
+
* double-count the call.
|
|
33
|
+
*/
|
|
34
|
+
readonly recordKey: string;
|
|
35
|
+
/** Agent that made the call — a sub-agent records under its own id. */
|
|
36
|
+
readonly agentId: string;
|
|
37
|
+
/** Provenance path from the root agent down to `agentId`. */
|
|
38
|
+
readonly callPath: readonly string[];
|
|
39
|
+
/** Scope ids as attribution: `analysisId` or `targetAssessmentId`. */
|
|
40
|
+
readonly scope: Scope;
|
|
41
|
+
/** Present only for calls made inside a run (the session carries a `RunFrame`). */
|
|
42
|
+
readonly runId?: string;
|
|
43
|
+
/** Present only for calls made inside a run step. */
|
|
44
|
+
readonly stepId?: string;
|
|
45
|
+
/** Model the harness asked for; absent when the provider does not report it. */
|
|
46
|
+
readonly requestedModelId?: string;
|
|
47
|
+
/** Model that actually answered; absent when the endpoint does not report it. */
|
|
48
|
+
readonly servedModelId?: string;
|
|
49
|
+
/** What the provider reported. Unreported figures stay absent, never zeroed. */
|
|
50
|
+
readonly usage: ChatUsage;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Records one `LlmUsageRecord` per completed LLM call.
|
|
54
|
+
*
|
|
55
|
+
* Fire-and-forget: the loop neither awaits `record` nor guards it, so a
|
|
56
|
+
* realization MUST NOT throw and MUST NOT block — buffer and flush
|
|
57
|
+
* internally, and own your error handling (diagnostics belong on the injected
|
|
58
|
+
* `Logger`). A recorder that violates the contract fails or stalls the run it
|
|
59
|
+
* was only meant to observe.
|
|
60
|
+
*/
|
|
61
|
+
export interface UsageRecorder {
|
|
62
|
+
record(record: LlmUsageRecord): void;
|
|
63
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `UsageRecorder` — the per-call LLM usage-accounting seam.
|
|
3
|
+
*
|
|
4
|
+
* Sibling of `ResolveBilling` and `RunCharge`, and complementary to both:
|
|
5
|
+
* `ResolveBilling` stamps attribution onto a wire call, `RunCharge` brackets a
|
|
6
|
+
* run for managed billing, and `UsageRecorder` streams the fine-grained token
|
|
7
|
+
* telemetry every completed LLM call produces. The harness names no storage or
|
|
8
|
+
* display technology — it emits records; the embedder decides where they land.
|
|
9
|
+
*
|
|
10
|
+
* The loop is the single delivery site (it sees every reply in both execution
|
|
11
|
+
* modes and already holds the session), so a realization is wired once at the
|
|
12
|
+
* composition root and reaches every `runAgent` invocation through the deps
|
|
13
|
+
* bags. OSS default: `createNoopUsageRecorder` (`./noop-usage-recorder.ts`).
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
@@ -10,6 +10,7 @@
|
|
|
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 { TokenUsageRollup } from "./usage.js";
|
|
13
14
|
/**
|
|
14
15
|
* Provenance stamped on every chat-stream event: the emitting agent and the
|
|
15
16
|
* call chain that reached it (e.g. `["conversation-agent"]`, or
|
|
@@ -25,6 +26,28 @@ export interface TextDeltaEvent {
|
|
|
25
26
|
text: string;
|
|
26
27
|
source: EventSource;
|
|
27
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* How a tool call ended.
|
|
31
|
+
*
|
|
32
|
+
* Three states, not a boolean: a user who rejects an approval made a decision,
|
|
33
|
+
* and reporting that decision as a fault misdescribes it. The loop already
|
|
34
|
+
* separates the two in its control flow — a denial ends the turn, an error is
|
|
35
|
+
* one the model reads and retries around — so the observation channel carries
|
|
36
|
+
* the same distinction. One field rather than two booleans, because two would
|
|
37
|
+
* admit the impossible "not an error, but denied".
|
|
38
|
+
*/
|
|
39
|
+
export type ToolOutcome = "ok" | "error" | "denied";
|
|
40
|
+
/**
|
|
41
|
+
* One line naming what a tool call is doing, produced by the tool's own
|
|
42
|
+
* `describeCall` hook and normalized at the emit site.
|
|
43
|
+
*
|
|
44
|
+
* Opaque display text. A consumer renders it and derives nothing from it — no
|
|
45
|
+
* splitting, no keying on separators. The contract is harness-owned so it can
|
|
46
|
+
* widen when a renderer needs structure; parsing it would recreate the schema
|
|
47
|
+
* coupling the hook exists to remove. Absent when the tool declares no hook, or
|
|
48
|
+
* when the detail could not be produced.
|
|
49
|
+
*/
|
|
50
|
+
export type ToolCallDetail = string;
|
|
28
51
|
/** A tool call has been dispatched. */
|
|
29
52
|
export interface ToolStartedEvent {
|
|
30
53
|
type: "tool-started";
|
|
@@ -32,6 +55,8 @@ export interface ToolStartedEvent {
|
|
|
32
55
|
toolUseId: string;
|
|
33
56
|
/** The tool name. */
|
|
34
57
|
name: string;
|
|
58
|
+
/** See {@link ToolCallDetail}. Absent — never empty — when none was produced. */
|
|
59
|
+
detail?: ToolCallDetail;
|
|
35
60
|
source: EventSource;
|
|
36
61
|
}
|
|
37
62
|
/** A tool call has resolved. */
|
|
@@ -39,14 +64,30 @@ export interface ToolFinishedEvent {
|
|
|
39
64
|
type: "tool-finished";
|
|
40
65
|
toolUseId: string;
|
|
41
66
|
name: string;
|
|
42
|
-
/**
|
|
43
|
-
|
|
67
|
+
/** How the call ended. See {@link ToolOutcome}. */
|
|
68
|
+
outcome: ToolOutcome;
|
|
69
|
+
/** The same detail the matching `tool-started` carried. */
|
|
70
|
+
detail?: ToolCallDetail;
|
|
44
71
|
source: EventSource;
|
|
45
72
|
}
|
|
46
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* The agent loop produced its terminal reply — the turn is complete.
|
|
75
|
+
*
|
|
76
|
+
* Both rollups are absent whenever no covered call reported usage; neither is
|
|
77
|
+
* ever an all-zero figure. A turn that dies instead of finishing emits
|
|
78
|
+
* `ChatErrorEvent` and therefore no rollup at all — the usage-record ledger,
|
|
79
|
+
* not this event, is the complete account of what a turn spent.
|
|
80
|
+
*/
|
|
47
81
|
export interface FinishEvent {
|
|
48
82
|
type: "finish";
|
|
49
83
|
source: EventSource;
|
|
84
|
+
/** What this loop's own LLM calls used, the forced wrap-up included. */
|
|
85
|
+
usage?: TokenUsageRollup;
|
|
86
|
+
/**
|
|
87
|
+
* The whole turn's total — this loop's calls plus every descendant loop's
|
|
88
|
+
* (sub-agent tools included). Present only on the turn's root loop.
|
|
89
|
+
*/
|
|
90
|
+
turnUsage?: TokenUsageRollup;
|
|
50
91
|
}
|
|
51
92
|
/** The turn failed. `reason` is a machine-readable code when one applies. */
|
|
52
93
|
export interface ChatErrorEvent {
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* Run lifecycle: run-started, dag-state, run-completed, run-failed, run-synthesis,
|
|
10
10
|
* synthesis-progress
|
|
11
11
|
* Per-step live: step-activity, step-file-tree
|
|
12
|
-
* Per-step final: step-output, step-summary
|
|
12
|
+
* Per-step final: step-output, step-summary, step-usage
|
|
13
13
|
*/
|
|
14
|
+
import type { TokenUsageRollup } from "./usage.js";
|
|
14
15
|
export interface PlanStep {
|
|
15
16
|
id: string;
|
|
16
17
|
name: string;
|
|
@@ -201,6 +202,36 @@ export interface StepSummaryPart {
|
|
|
201
202
|
/** Free-form markdown body. Render with a markdown renderer. */
|
|
202
203
|
markdown: string;
|
|
203
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* What one analysis-run step's agent loop reported spending, emitted when that
|
|
207
|
+
* loop completes.
|
|
208
|
+
*
|
|
209
|
+
* `usage` is the step's rollup and is required: a part exists to carry one, so a
|
|
210
|
+
* step whose loop reported nothing emits no part at all rather than one with an
|
|
211
|
+
* absent or zeroed figure. Per-call granularity is the usage-record ledger's
|
|
212
|
+
* job, never this part's.
|
|
213
|
+
*
|
|
214
|
+
* Scoped to analysis runs. Workflows without step parts (target assessment,
|
|
215
|
+
* ephemeral runs, data profiling) reach the ledger through the recorder seam and
|
|
216
|
+
* carry no usage part.
|
|
217
|
+
*/
|
|
218
|
+
export interface StepUsagePart {
|
|
219
|
+
type: "data-step-usage";
|
|
220
|
+
/** Stable ID for reconciliation — unique per step within a run. */
|
|
221
|
+
id: string;
|
|
222
|
+
runId: string;
|
|
223
|
+
stepId: string;
|
|
224
|
+
agentId: string;
|
|
225
|
+
/**
|
|
226
|
+
* The model id the step's agent was configured to run under — the identity
|
|
227
|
+
* the rollup is attributable to. Whether the endpoint actually served that
|
|
228
|
+
* model is a per-call question the usage-record ledger answers; a rollup
|
|
229
|
+
* spans calls and cannot.
|
|
230
|
+
*/
|
|
231
|
+
modelId: string;
|
|
232
|
+
/** Summed token usage across this step loop's LLM calls. */
|
|
233
|
+
usage: TokenUsageRollup;
|
|
234
|
+
}
|
|
204
235
|
/**
|
|
205
236
|
* Emitted when a step agent declares it cannot fulfil its step via
|
|
206
237
|
* `report_blocker` (see the harness-sandbox-agents spec). A blocked step has no deliverables; the
|
|
@@ -233,6 +264,11 @@ export interface RunCompletedPart {
|
|
|
233
264
|
* to explain why (e.g., synthesis failed but step summaries are available).
|
|
234
265
|
*/
|
|
235
266
|
note?: string;
|
|
267
|
+
/**
|
|
268
|
+
* The run's aggregate token usage — the sum of what its steps reported.
|
|
269
|
+
* Absent when no step reported any, never an all-zero figure.
|
|
270
|
+
*/
|
|
271
|
+
usage?: TokenUsageRollup;
|
|
236
272
|
}
|
|
237
273
|
export interface SynthesizedFinding {
|
|
238
274
|
stepId: string;
|
|
@@ -323,4 +359,4 @@ export interface DataPreviewFailedPart {
|
|
|
323
359
|
/** Optional taxonomy of failure kinds. */
|
|
324
360
|
errorKind?: "render" | "submit" | "build" | "timeout" | "internal";
|
|
325
361
|
}
|
|
326
|
-
export type CortexChatPart = PresentationPart | PlanPart | RunCardPart | FileReferencePart | AskPart | RunStartedPart | DagStatePart | StepActivityPart | StepFileTreePart | StepOutputPart | StepSummaryPart | StepBlockedPart | RunSynthesisPart | SynthesisProgressPart | RunCompletedPart | RunFailedPart | PreviewPart | DataPreviewFailedPart;
|
|
362
|
+
export type CortexChatPart = PresentationPart | PlanPart | RunCardPart | FileReferencePart | AskPart | RunStartedPart | DagStatePart | StepActivityPart | StepFileTreePart | StepOutputPart | StepSummaryPart | StepUsagePart | StepBlockedPart | RunSynthesisPart | SynthesisProgressPart | RunCompletedPart | RunFailedPart | PreviewPart | DataPreviewFailedPart;
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
* Run lifecycle: run-started, dag-state, run-completed, run-failed, run-synthesis,
|
|
10
10
|
* synthesis-progress
|
|
11
11
|
* Per-step live: step-activity, step-file-tree
|
|
12
|
-
* Per-step final: step-output, step-summary
|
|
12
|
+
* Per-step final: step-output, step-summary, step-usage
|
|
13
13
|
*/
|
|
14
14
|
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data profile's durable-frame identity, on the Cortex wire vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* This lives in `contracts/` — not beside the workflow that stamps it — for the same reason every
|
|
5
|
+
* other name here does: it is a value a CONSUMER reads back, and `contracts/` is the one part of the
|
|
6
|
+
* package a consumer can import without inheriting the harness's own dependencies. The workflow
|
|
7
|
+
* module that uses it pulls in DBOS, the sandbox client, and the profiler agent graph; a host that
|
|
8
|
+
* imported the literal from there would pay ~120ms of module loading to obtain a string, on every
|
|
9
|
+
* command that touches its ledger.
|
|
10
|
+
*
|
|
11
|
+
* That is not a packaging detail to be worked around at the call site. A constant whose whole purpose
|
|
12
|
+
* is to be compared against stored data belongs where the data's vocabulary is declared.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The `runId` the harness stamps on every LLM call the data profile makes.
|
|
16
|
+
*
|
|
17
|
+
* A literal, not a minted id: the profile has no run row in any ledger, so this is the only thing
|
|
18
|
+
* identifying its work as the profile's. A consumer needs it to READ BACK what the harness recorded —
|
|
19
|
+
* usage accounting carries one run-id column, so a host reporting consumption "by run" finds profile
|
|
20
|
+
* calls sitting among real runs and can separate them only by comparing against this value.
|
|
21
|
+
*
|
|
22
|
+
* Exported rather than merely documented so that comparison is a compile-time coupling. A host
|
|
23
|
+
* holding its own copy of the string would keep compiling through a rename here, and quietly resume
|
|
24
|
+
* reporting the profile as an unnamed run — a failure with no red test anywhere.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DATA_PROFILE_RUN_LITERAL: "data-profile";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data profile's durable-frame identity, on the Cortex wire vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* This lives in `contracts/` — not beside the workflow that stamps it — for the same reason every
|
|
5
|
+
* other name here does: it is a value a CONSUMER reads back, and `contracts/` is the one part of the
|
|
6
|
+
* package a consumer can import without inheriting the harness's own dependencies. The workflow
|
|
7
|
+
* module that uses it pulls in DBOS, the sandbox client, and the profiler agent graph; a host that
|
|
8
|
+
* imported the literal from there would pay ~120ms of module loading to obtain a string, on every
|
|
9
|
+
* command that touches its ledger.
|
|
10
|
+
*
|
|
11
|
+
* That is not a packaging detail to be worked around at the call site. A constant whose whole purpose
|
|
12
|
+
* is to be compared against stored data belongs where the data's vocabulary is declared.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The `runId` the harness stamps on every LLM call the data profile makes.
|
|
16
|
+
*
|
|
17
|
+
* A literal, not a minted id: the profile has no run row in any ledger, so this is the only thing
|
|
18
|
+
* identifying its work as the profile's. A consumer needs it to READ BACK what the harness recorded —
|
|
19
|
+
* usage accounting carries one run-id column, so a host reporting consumption "by run" finds profile
|
|
20
|
+
* calls sitting among real runs and can separate them only by comparing against this value.
|
|
21
|
+
*
|
|
22
|
+
* Exported rather than merely documented so that comparison is a compile-time coupling. A host
|
|
23
|
+
* holding its own copy of the string would keep compiling through a rename here, and quietly resume
|
|
24
|
+
* reporting the profile as an unnamed run — a failure with no red test anywhere.
|
|
25
|
+
*/
|
|
26
|
+
export const DATA_PROFILE_RUN_LITERAL = "data-profile";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export type { PlanStep, PresentationContent, PresentationPart, PlanPart, RunCardPart, FileReferenceEntry, FileReferencePart, AskPart, RunStartedPart, StepStatus, DagStepState, DagStatePart, StepPhase, StepActivityPart, FileTreeEntry, StepFileTreePart, StepOutputFile, StepOutputPart, StepSummaryPart, StepBlockedPart, SynthesizedFinding, BiologicalTheme, RunSynthesisPart, SynthesisPhase, SynthesisProgressPart, RunCompletedFinding, RunCompletedPart, RunFailedPart, PreviewPart, DataPreviewFailedPart, CortexChatPart, } from "./chat-parts.js";
|
|
1
|
+
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, PreviewPart, DataPreviewFailedPart, CortexChatPart, } from "./chat-parts.js";
|
|
2
2
|
export type { EventSource, TextDeltaEvent, ToolStartedEvent, ToolFinishedEvent, FinishEvent, ChatErrorEvent, CortexChatEvent } from "./chat-events.js";
|
|
3
|
+
export type { TokenUsageRollup } from "./usage.js";
|
|
4
|
+
export { DATA_PROFILE_RUN_LITERAL } from "./data-profile.js";
|
|
3
5
|
export type { TextPart, ToolCallPart, CortexPart, CortexMessage } from "./message.js";
|
|
4
6
|
export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./part-registry.js";
|
|
5
7
|
export type { CortexChatPartType, PartDescriptor, PartEmitter, PartConsumer } from "./part-registry.js";
|
package/dist/contracts/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { DATA_PROFILE_RUN_LITERAL } from "./data-profile.js";
|
|
1
2
|
export { PART_REGISTRY, isTransient, isReconciling, isSidebarPart } from "./part-registry.js";
|
|
2
3
|
export { AnalogyCoverageSchema, AnalogyReportSchema, AnalogyReportErrorSchema, AnalogicalReasonerOutputSchema } from "./analogy-report.js";
|
|
3
4
|
export { CoverageSchema, EntitySchema, SummarySchema, LiabilitySummarySchema, TractabilitySchema, IndicationsSchema, DrugInteractionsSchema, ClinicalDevelopmentSchema, SafetyProfileSchema, OffTissueRiskSchema, EvidenceConflictsSchema, EvidenceTimelineSchema, TranslationalChainSchema, AdditionalEvidenceSchema, DiscoveryTrialsSchema, DossierSchema, DossierSchemaV3Legacy, DossierV4Schema, DossierV5Schema, DossierV5BodySchema, ClinicalTrialAttributionV5Schema, ClinicalDevelopmentV5Schema, RegulatoryActionRowV5Schema, QualityGateStatusSchema, QualityGatesSchema, LiabilitySummaryV4Schema, ClinicalDevelopmentV4Schema, SafetyProfileV4Schema, OrganRiskRowV4Schema, ReferenceBiologyV4Shape, isDossier, dossierJsonSchema, SECTION_BLURBS, TargetAssessmentPhaseSchema, TargetAssessmentProgressEventSchema, } from "./target-dossier.js";
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* discriminant is `type`, so `switch (part.type) { case "data-report-preview": ... }`
|
|
7
7
|
* narrows the union member without any `as` cast.
|
|
8
8
|
*/
|
|
9
|
+
import type { ToolCallDetail, ToolOutcome } from "./chat-events.js";
|
|
9
10
|
import type { CortexChatPart } from "./chat-parts.js";
|
|
11
|
+
import type { TokenUsageRollup } from "./usage.js";
|
|
10
12
|
/** A plain assistant/user text run. */
|
|
11
13
|
export interface TextPart {
|
|
12
14
|
type: "text";
|
|
@@ -24,7 +26,13 @@ export interface ToolCallPart {
|
|
|
24
26
|
toolCallId: string;
|
|
25
27
|
toolName: string;
|
|
26
28
|
status: "started" | "finished";
|
|
27
|
-
|
|
29
|
+
/**
|
|
30
|
+
* How the call ended. Absent while `status` is `"started"` — the outcome is
|
|
31
|
+
* not known yet. See {@link ToolOutcome}.
|
|
32
|
+
*/
|
|
33
|
+
outcome?: ToolOutcome;
|
|
34
|
+
/** See {@link ToolCallDetail}. Absent when no detail was produced. */
|
|
35
|
+
detail?: ToolCallDetail;
|
|
28
36
|
}
|
|
29
37
|
/** The discriminated union of every part the chat path can carry. */
|
|
30
38
|
export type CortexPart = TextPart | ToolCallPart | CortexChatPart;
|
|
@@ -39,4 +47,16 @@ export interface CortexMessage {
|
|
|
39
47
|
* existing consumer is unaffected.
|
|
40
48
|
*/
|
|
41
49
|
interrupted?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* What providers reported for the TURN this message completed — the same
|
|
52
|
+
* figure `FinishEvent.turnUsage` carries to a live surface, so a reloaded
|
|
53
|
+
* transcript renders what the live turn rendered. Carried only on the
|
|
54
|
+
* assistant message that ended a turn.
|
|
55
|
+
*
|
|
56
|
+
* Absent means no figure was reported: a turn whose calls reported nothing, a
|
|
57
|
+
* message stored before rollups were persisted, or any message that did not
|
|
58
|
+
* end a turn. Never an all-zero rollup — "spent nothing" and "was told
|
|
59
|
+
* nothing" stay distinguishable.
|
|
60
|
+
*/
|
|
61
|
+
usage?: TokenUsageRollup;
|
|
42
62
|
}
|
|
@@ -10,6 +10,7 @@ export const PART_REGISTRY = {
|
|
|
10
10
|
"data-step-file-tree": { emitter: "workflow", consumer: "sidebar", transient: true, reconciling: true },
|
|
11
11
|
"data-step-output": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
|
|
12
12
|
"data-step-summary": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
|
|
13
|
+
"data-step-usage": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
|
|
13
14
|
"data-step-blocked": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
|
|
14
15
|
"data-run-synthesis": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: false },
|
|
15
16
|
"data-synthesis-progress": { emitter: "workflow", consumer: "sidebar", transient: false, reconciling: true },
|
|
@@ -14,10 +14,17 @@ export declare const TextDeltaEventSchema: z.ZodObject<{
|
|
|
14
14
|
callPath: z.ZodArray<z.ZodString>;
|
|
15
15
|
}, z.core.$strip>;
|
|
16
16
|
}, z.core.$strip>;
|
|
17
|
+
/** Mirrors the `ToolOutcome` union — three states, never a boolean. */
|
|
18
|
+
export declare const ToolOutcomeSchema: z.ZodEnum<{
|
|
19
|
+
error: "error";
|
|
20
|
+
ok: "ok";
|
|
21
|
+
denied: "denied";
|
|
22
|
+
}>;
|
|
17
23
|
export declare const ToolStartedEventSchema: z.ZodObject<{
|
|
18
24
|
type: z.ZodLiteral<"tool-started">;
|
|
19
25
|
toolUseId: z.ZodString;
|
|
20
26
|
name: z.ZodString;
|
|
27
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
21
28
|
source: z.ZodObject<{
|
|
22
29
|
agentId: z.ZodString;
|
|
23
30
|
callPath: z.ZodArray<z.ZodString>;
|
|
@@ -27,7 +34,12 @@ export declare const ToolFinishedEventSchema: z.ZodObject<{
|
|
|
27
34
|
type: z.ZodLiteral<"tool-finished">;
|
|
28
35
|
toolUseId: z.ZodString;
|
|
29
36
|
name: z.ZodString;
|
|
30
|
-
|
|
37
|
+
outcome: z.ZodEnum<{
|
|
38
|
+
error: "error";
|
|
39
|
+
ok: "ok";
|
|
40
|
+
denied: "denied";
|
|
41
|
+
}>;
|
|
42
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
31
43
|
source: z.ZodObject<{
|
|
32
44
|
agentId: z.ZodString;
|
|
33
45
|
callPath: z.ZodArray<z.ZodString>;
|
|
@@ -39,6 +51,20 @@ export declare const FinishEventSchema: z.ZodObject<{
|
|
|
39
51
|
agentId: z.ZodString;
|
|
40
52
|
callPath: z.ZodArray<z.ZodString>;
|
|
41
53
|
}, z.core.$strip>;
|
|
54
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
55
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
cacheCreationInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
cacheReadInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
reasoningTokens: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
}, z.core.$strip>>;
|
|
61
|
+
turnUsage: z.ZodOptional<z.ZodObject<{
|
|
62
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
63
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
64
|
+
cacheCreationInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
65
|
+
cacheReadInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
reasoningTokens: z.ZodOptional<z.ZodNumber>;
|
|
67
|
+
}, z.core.$strip>>;
|
|
42
68
|
}, z.core.$strip>;
|
|
43
69
|
export declare const ChatErrorEventSchema: z.ZodObject<{
|
|
44
70
|
type: z.ZodLiteral<"error">;
|
|
@@ -60,6 +86,7 @@ export declare const CortexChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
60
86
|
type: z.ZodLiteral<"tool-started">;
|
|
61
87
|
toolUseId: z.ZodString;
|
|
62
88
|
name: z.ZodString;
|
|
89
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
63
90
|
source: z.ZodObject<{
|
|
64
91
|
agentId: z.ZodString;
|
|
65
92
|
callPath: z.ZodArray<z.ZodString>;
|
|
@@ -68,7 +95,12 @@ export declare const CortexChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
68
95
|
type: z.ZodLiteral<"tool-finished">;
|
|
69
96
|
toolUseId: z.ZodString;
|
|
70
97
|
name: z.ZodString;
|
|
71
|
-
|
|
98
|
+
outcome: z.ZodEnum<{
|
|
99
|
+
error: "error";
|
|
100
|
+
ok: "ok";
|
|
101
|
+
denied: "denied";
|
|
102
|
+
}>;
|
|
103
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
72
104
|
source: z.ZodObject<{
|
|
73
105
|
agentId: z.ZodString;
|
|
74
106
|
callPath: z.ZodArray<z.ZodString>;
|
|
@@ -79,6 +111,20 @@ export declare const CortexChatEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
79
111
|
agentId: z.ZodString;
|
|
80
112
|
callPath: z.ZodArray<z.ZodString>;
|
|
81
113
|
}, z.core.$strip>;
|
|
114
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
115
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
116
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
117
|
+
cacheCreationInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
118
|
+
cacheReadInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
119
|
+
reasoningTokens: z.ZodOptional<z.ZodNumber>;
|
|
120
|
+
}, z.core.$strip>>;
|
|
121
|
+
turnUsage: z.ZodOptional<z.ZodObject<{
|
|
122
|
+
inputTokens: z.ZodOptional<z.ZodNumber>;
|
|
123
|
+
outputTokens: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
cacheCreationInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
125
|
+
cacheReadInputTokens: z.ZodOptional<z.ZodNumber>;
|
|
126
|
+
reasoningTokens: z.ZodOptional<z.ZodNumber>;
|
|
127
|
+
}, z.core.$strip>>;
|
|
82
128
|
}, z.core.$strip>, z.ZodObject<{
|
|
83
129
|
type: z.ZodLiteral<"error">;
|
|
84
130
|
message: z.ZodString;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Zod schemas for Cortex-native chat-stream events — validation at boundaries.
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { TokenUsageRollupSchema } from "./usage.js";
|
|
5
6
|
export const EventSourceSchema = z.object({
|
|
6
7
|
agentId: z.string(),
|
|
7
8
|
callPath: z.array(z.string()),
|
|
@@ -11,22 +12,28 @@ export const TextDeltaEventSchema = z.object({
|
|
|
11
12
|
text: z.string(),
|
|
12
13
|
source: EventSourceSchema,
|
|
13
14
|
});
|
|
15
|
+
/** Mirrors the `ToolOutcome` union — three states, never a boolean. */
|
|
16
|
+
export const ToolOutcomeSchema = z.enum(["ok", "error", "denied"]);
|
|
14
17
|
export const ToolStartedEventSchema = z.object({
|
|
15
18
|
type: z.literal("tool-started"),
|
|
16
19
|
toolUseId: z.string(),
|
|
17
20
|
name: z.string(),
|
|
21
|
+
detail: z.string().optional(),
|
|
18
22
|
source: EventSourceSchema,
|
|
19
23
|
});
|
|
20
24
|
export const ToolFinishedEventSchema = z.object({
|
|
21
25
|
type: z.literal("tool-finished"),
|
|
22
26
|
toolUseId: z.string(),
|
|
23
27
|
name: z.string(),
|
|
24
|
-
|
|
28
|
+
outcome: ToolOutcomeSchema,
|
|
29
|
+
detail: z.string().optional(),
|
|
25
30
|
source: EventSourceSchema,
|
|
26
31
|
});
|
|
27
32
|
export const FinishEventSchema = z.object({
|
|
28
33
|
type: z.literal("finish"),
|
|
29
34
|
source: EventSourceSchema,
|
|
35
|
+
usage: TokenUsageRollupSchema.optional(),
|
|
36
|
+
turnUsage: TokenUsageRollupSchema.optional(),
|
|
30
37
|
});
|
|
31
38
|
export const ChatErrorEventSchema = z.object({
|
|
32
39
|
type: z.literal("error"),
|