voratiq 0.1.0-beta.25 → 0.1.0-beta.26

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 CHANGED
@@ -15,7 +15,7 @@ npm install -g voratiq
15
15
 
16
16
  - Node 20+
17
17
  - git
18
- - 1+ AI coding agent (Claude [>=2.1.111](https://github.com/anthropics/claude-code?tab=readme-ov-file#get-started), Codex [>=0.122.0](https://github.com/openai/codex?tab=readme-ov-file#quickstart), or Gemini [>=0.31.0](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quick-install))
18
+ - 1+ AI coding agent (Claude [>=2.1.111](https://github.com/anthropics/claude-code?tab=readme-ov-file#get-started), Codex [>=0.122.0](https://github.com/openai/codex?tab=readme-ov-file#quickstart), or Gemini [>=0.40.0](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quick-install))
19
19
  - macOS: `ripgrep`
20
20
  - Linux (Debian/Ubuntu): `bubblewrap`, `socat`, `ripgrep`
21
21
 
@@ -42,7 +42,7 @@ export async function runSandboxedAgent(input) {
42
42
  runtimeManifestPath: paths.runtimeManifestPath,
43
43
  promptPath,
44
44
  workspacePath: paths.workspacePath,
45
- env: staged.env,
45
+ env: applyProviderRunEnvironmentOverrides(providerId, staged.env),
46
46
  environment,
47
47
  });
48
48
  const denialBackoff = resolveDenialBackoff({
@@ -111,6 +111,15 @@ export async function runSandboxedAgent(input) {
111
111
  }
112
112
  }
113
113
  }
114
+ function applyProviderRunEnvironmentOverrides(providerId, env) {
115
+ if (providerId !== "gemini") {
116
+ return env;
117
+ }
118
+ return {
119
+ ...env,
120
+ GEMINI_CLI_TRUST_WORKSPACE: "true",
121
+ };
122
+ }
114
123
  function resolveDenialBackoff(options) {
115
124
  if (options.override) {
116
125
  return options.override;
@@ -5,6 +5,7 @@ import { readRunRecords, } from "../../domain/run/persistence/adapter.js";
5
5
  import { readSpecRecords, } from "../../domain/spec/persistence/adapter.js";
6
6
  import { TERMINAL_VERIFICATION_STATUSES } from "../../domain/verify/model/types.js";
7
7
  import { readVerificationRecords, } from "../../domain/verify/persistence/adapter.js";
8
+ import { loadVerificationSelectionPolicyOutput } from "../../policy/index.js";
8
9
  import { renderInteractiveTranscript } from "../../render/transcripts/interactive.js";
9
10
  import { renderInteractiveListTable, renderListTableTranscript, renderMessageListTable, renderReduceListTable, renderRunListTable, renderSpecListTable, renderVerifyListTable, } from "../../render/transcripts/list.js";
10
11
  import { formatMessageElapsed, formatMessageRecipientDuration, renderMessageTranscript, } from "../../render/transcripts/message.js";
@@ -13,6 +14,7 @@ import { renderRunTranscript } from "../../render/transcripts/run.js";
13
14
  import { formatSpecAgentDuration, formatSpecElapsed, renderSpecTranscript, } from "../../render/transcripts/spec.js";
14
15
  import { formatVerifyElapsed, renderVerifyTranscript, } from "../../render/transcripts/verify.js";
15
16
  import { formatRenderLifecycleDuration, formatRenderLifecycleRowDuration, } from "../../render/utils/duration.js";
17
+ import { toErrorMessage } from "../../utils/errors.js";
16
18
  import { pathExists } from "../../utils/fs.js";
17
19
  import { formatTargetDisplay, formatTargetTablePreview, normalizeListDetailSession, normalizeListSession, toListJsonTargetRef, } from "./normalization.js";
18
20
  import { getListRecordId } from "./records.js";
@@ -62,7 +64,7 @@ async function executeDetailMode(input) {
62
64
  limit: 1,
63
65
  predicate: (record) => getRecordId(operator, record) === sessionId,
64
66
  });
65
- const warnings = query.warnings;
67
+ const warnings = [...query.warnings];
66
68
  const record = query.records[0];
67
69
  if (!record) {
68
70
  return {
@@ -78,6 +80,15 @@ async function executeDetailMode(input) {
78
80
  };
79
81
  }
80
82
  const detailSession = normalizeListDetailSession(operator, record);
83
+ const selection = await resolveListDetailVerificationSelection({
84
+ root: input.root,
85
+ operator,
86
+ record,
87
+ warnings,
88
+ });
89
+ const jsonSession = selection
90
+ ? { ...detailSession, selection }
91
+ : detailSession;
81
92
  return {
82
93
  warnings,
83
94
  output: renderDetailOutput(operator, detailSession, {
@@ -87,7 +98,7 @@ async function executeDetailMode(input) {
87
98
  json: {
88
99
  operator,
89
100
  mode: "detail",
90
- session: toJsonDetailSession(detailSession),
101
+ session: toJsonDetailSession(jsonSession),
91
102
  warnings,
92
103
  },
93
104
  };
@@ -337,6 +348,7 @@ function toJsonDetailSession(session) {
337
348
  ? { description: session.description }
338
349
  : {}),
339
350
  agents: session.agents.map(toJsonAgent),
351
+ ...(session.selection ? { selection: session.selection } : {}),
340
352
  };
341
353
  }
342
354
  function toJsonAgent(agent) {
@@ -471,6 +483,52 @@ function getRecordId(operator, record) {
471
483
  function formatSessionWarning(warning) {
472
484
  return `Ignoring corrupt session ${warning.displayPath}`;
473
485
  }
486
+ async function resolveListDetailVerificationSelection(options) {
487
+ const { root, operator, record, warnings } = options;
488
+ if (operator !== "verify") {
489
+ return undefined;
490
+ }
491
+ const verificationRecord = record;
492
+ if (!TERMINAL_VERIFICATION_STATUSES.includes(verificationRecord.status)) {
493
+ return undefined;
494
+ }
495
+ if (verificationRecord.status === "failed" ||
496
+ verificationRecord.status === "aborted") {
497
+ return {
498
+ state: "unresolved",
499
+ unresolvedReasons: [
500
+ {
501
+ code: "verification_not_succeeded",
502
+ status: verificationRecord.status,
503
+ },
504
+ ],
505
+ };
506
+ }
507
+ const output = await loadVerificationSelectionPolicyOutput({
508
+ root,
509
+ record: verificationRecord,
510
+ }).catch((error) => {
511
+ warnings.push(`Verification selection unavailable: ${toErrorMessage(error)}`);
512
+ return undefined;
513
+ });
514
+ if (!output) {
515
+ return undefined;
516
+ }
517
+ if (output.warnings) {
518
+ warnings.push(...output.warnings);
519
+ }
520
+ const decision = output.decision;
521
+ if (decision.state === "resolvable") {
522
+ return {
523
+ state: "resolvable",
524
+ selectedCanonicalAgentId: decision.selectedCanonicalAgentId,
525
+ };
526
+ }
527
+ return {
528
+ state: "unresolved",
529
+ unresolvedReasons: decision.unresolvedReasons,
530
+ };
531
+ }
474
532
  function formatVerifyAgentDuration(agent) {
475
533
  return formatRenderLifecycleRowDuration({
476
534
  lifecycle: {
@@ -1,4 +1,4 @@
1
- import type { ListJsonArtifact, ListJsonChanges, ListJsonTargetRef, ListOperator } from "../../contracts/list.js";
1
+ import type { ListJsonArtifact, ListJsonChanges, ListJsonTargetRef, ListJsonVerificationSelection, ListOperator } from "../../contracts/list.js";
2
2
  export { formatTargetDisplay, formatTargetTablePreview, TARGET_TABLE_PREVIEW_LENGTH, } from "../../utils/list-target.js";
3
3
  import { type ListRecord } from "./records.js";
4
4
  export type ListTargetOperator = ListOperator;
@@ -43,6 +43,7 @@ export interface NormalizedListDetailSession extends NormalizedListSession {
43
43
  completedAt?: string;
44
44
  workspacePath: string;
45
45
  agents: NormalizedListAgent[];
46
+ selection?: ListJsonVerificationSelection;
46
47
  }
47
48
  export declare function normalizeListSession(operator: ListOperator, record: ListOperatorRecord): NormalizedListSession;
48
49
  export declare function normalizeListDetailSession(operator: ListOperator, record: ListOperatorRecord): NormalizedListDetailSession;
@@ -21,7 +21,8 @@ const GEMINI_DEFAULT_ARGV = [
21
21
  MODEL_PLACEHOLDER,
22
22
  "--output-format",
23
23
  "json",
24
- "--yolo",
24
+ "--approval-mode",
25
+ "yolo",
25
26
  ];
26
27
  const DEFAULT_ARGV_BY_PROVIDER = {
27
28
  claude: CLAUDE_DEFAULT_ARGV,
@@ -177,25 +178,15 @@ const DEFAULT_AGENT_CATALOG_ENTRIES = [
177
178
  extraArgs: ["--config", "model_reasoning_effort=xhigh"],
178
179
  },
179
180
  {
180
- id: "gemini-2-5-flash",
181
+ id: "gemini-3-1-flash-lite-preview",
181
182
  provider: "gemini",
182
- model: "gemini-2.5-flash",
183
- },
184
- {
185
- id: "gemini-2-5-flash-lite",
186
- provider: "gemini",
187
- model: "gemini-2.5-flash-lite",
183
+ model: "gemini-3.1-flash-lite-preview",
188
184
  },
189
185
  {
190
186
  id: "gemini-3-flash-preview",
191
187
  provider: "gemini",
192
188
  model: "gemini-3-flash-preview",
193
189
  },
194
- {
195
- id: "gemini-2-5-pro",
196
- provider: "gemini",
197
- model: "gemini-2.5-pro",
198
- },
199
190
  {
200
191
  id: "gemini-3-1-pro-preview",
201
192
  provider: "gemini",
@@ -235,9 +226,9 @@ const LITE_AGENT_PRESET_ENTRIES = [
235
226
  model: "gpt-5.4-mini",
236
227
  },
237
228
  {
238
- id: "gemini-3-flash-preview",
229
+ id: "gemini-3-1-flash-lite-preview",
239
230
  provider: "gemini",
240
- model: "gemini-3-flash-preview",
231
+ model: "gemini-3.1-flash-lite-preview",
241
232
  runOnly: true,
242
233
  },
243
234
  ];
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import type { SelectionDecisionUnresolvedReason } from "../policy/result.js";
2
3
  export declare const listOperators: readonly ["spec", "run", "reduce", "verify", "message", "interactive"];
3
4
  export declare const listModes: readonly ["summary", "detail"];
4
5
  export type ListOperator = (typeof listOperators)[number];
@@ -42,12 +43,24 @@ export interface ListJsonAgent {
42
43
  changes?: ListJsonChanges;
43
44
  artifacts: ListJsonArtifact[];
44
45
  }
46
+ export type ListJsonVerificationSelectionUnresolvedReason = SelectionDecisionUnresolvedReason | {
47
+ code: "verification_not_succeeded";
48
+ status: "failed" | "aborted";
49
+ };
50
+ export type ListJsonVerificationSelection = {
51
+ state: "resolvable";
52
+ selectedCanonicalAgentId: string;
53
+ } | {
54
+ state: "unresolved";
55
+ unresolvedReasons: readonly ListJsonVerificationSelectionUnresolvedReason[];
56
+ };
45
57
  export interface ListJsonDetailSession extends ListJsonSessionBase {
46
58
  startedAt?: string;
47
59
  completedAt?: string;
48
60
  workspacePath: string;
49
61
  description?: string | null;
50
62
  agents: ListJsonAgent[];
63
+ selection?: ListJsonVerificationSelection;
51
64
  }
52
65
  export interface ListJsonSummaryOutput {
53
66
  operator: ListOperator;
@@ -74,6 +87,98 @@ export declare const listModeSchema: z.ZodEnum<{
74
87
  detail: "detail";
75
88
  summary: "summary";
76
89
  }>;
90
+ export declare const listJsonVerificationSelectionUnresolvedReasonSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
91
+ code: z.ZodLiteral<"no_successful_verifiers">;
92
+ failedVerifierAgentIds: z.ZodArray<z.ZodString>;
93
+ }, z.core.$loose>, z.ZodObject<{
94
+ code: z.ZodLiteral<"verifier_failed">;
95
+ failedVerifierAgentIds: z.ZodArray<z.ZodString>;
96
+ }, z.core.$loose>, z.ZodObject<{
97
+ code: z.ZodLiteral<"verifier_preference_missing">;
98
+ verifierAgentId: z.ZodString;
99
+ }, z.core.$loose>, z.ZodObject<{
100
+ code: z.ZodLiteral<"verifier_preference_unresolved">;
101
+ verifierAgentId: z.ZodString;
102
+ preferredCandidateId: z.ZodOptional<z.ZodString>;
103
+ resolvedPreferredCandidateId: z.ZodOptional<z.ZodString>;
104
+ }, z.core.$loose>, z.ZodObject<{
105
+ code: z.ZodLiteral<"verifier_disagreement">;
106
+ selections: z.ZodArray<z.ZodObject<{
107
+ verifierAgentId: z.ZodString;
108
+ selectedCanonicalAgentId: z.ZodString;
109
+ }, z.core.$loose>>;
110
+ }, z.core.$loose>, z.ZodObject<{
111
+ code: z.ZodLiteral<"selector_unresolved">;
112
+ selector: z.ZodString;
113
+ availableCanonicalAgentIds: z.ZodArray<z.ZodString>;
114
+ availableAliases: z.ZodArray<z.ZodString>;
115
+ }, z.core.$loose>, z.ZodObject<{
116
+ code: z.ZodLiteral<"selector_ambiguous">;
117
+ selector: z.ZodString;
118
+ resolutions: z.ZodArray<z.ZodObject<{
119
+ sourceId: z.ZodString;
120
+ selectedCanonicalAgentId: z.ZodString;
121
+ }, z.core.$loose>>;
122
+ }, z.core.$loose>, z.ZodObject<{
123
+ code: z.ZodLiteral<"selected_candidate_failed_programmatic">;
124
+ selectedCanonicalAgentId: z.ZodString;
125
+ eligibleCanonicalAgentIds: z.ZodArray<z.ZodString>;
126
+ }, z.core.$loose>, z.ZodObject<{
127
+ code: z.ZodLiteral<"verification_not_succeeded">;
128
+ status: z.ZodEnum<{
129
+ failed: "failed";
130
+ aborted: "aborted";
131
+ }>;
132
+ }, z.core.$loose>], "code">;
133
+ export declare const listJsonVerificationSelectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
134
+ state: z.ZodLiteral<"resolvable">;
135
+ selectedCanonicalAgentId: z.ZodString;
136
+ }, z.core.$strict>, z.ZodObject<{
137
+ state: z.ZodLiteral<"unresolved">;
138
+ unresolvedReasons: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
139
+ code: z.ZodLiteral<"no_successful_verifiers">;
140
+ failedVerifierAgentIds: z.ZodArray<z.ZodString>;
141
+ }, z.core.$loose>, z.ZodObject<{
142
+ code: z.ZodLiteral<"verifier_failed">;
143
+ failedVerifierAgentIds: z.ZodArray<z.ZodString>;
144
+ }, z.core.$loose>, z.ZodObject<{
145
+ code: z.ZodLiteral<"verifier_preference_missing">;
146
+ verifierAgentId: z.ZodString;
147
+ }, z.core.$loose>, z.ZodObject<{
148
+ code: z.ZodLiteral<"verifier_preference_unresolved">;
149
+ verifierAgentId: z.ZodString;
150
+ preferredCandidateId: z.ZodOptional<z.ZodString>;
151
+ resolvedPreferredCandidateId: z.ZodOptional<z.ZodString>;
152
+ }, z.core.$loose>, z.ZodObject<{
153
+ code: z.ZodLiteral<"verifier_disagreement">;
154
+ selections: z.ZodArray<z.ZodObject<{
155
+ verifierAgentId: z.ZodString;
156
+ selectedCanonicalAgentId: z.ZodString;
157
+ }, z.core.$loose>>;
158
+ }, z.core.$loose>, z.ZodObject<{
159
+ code: z.ZodLiteral<"selector_unresolved">;
160
+ selector: z.ZodString;
161
+ availableCanonicalAgentIds: z.ZodArray<z.ZodString>;
162
+ availableAliases: z.ZodArray<z.ZodString>;
163
+ }, z.core.$loose>, z.ZodObject<{
164
+ code: z.ZodLiteral<"selector_ambiguous">;
165
+ selector: z.ZodString;
166
+ resolutions: z.ZodArray<z.ZodObject<{
167
+ sourceId: z.ZodString;
168
+ selectedCanonicalAgentId: z.ZodString;
169
+ }, z.core.$loose>>;
170
+ }, z.core.$loose>, z.ZodObject<{
171
+ code: z.ZodLiteral<"selected_candidate_failed_programmatic">;
172
+ selectedCanonicalAgentId: z.ZodString;
173
+ eligibleCanonicalAgentIds: z.ZodArray<z.ZodString>;
174
+ }, z.core.$loose>, z.ZodObject<{
175
+ code: z.ZodLiteral<"verification_not_succeeded">;
176
+ status: z.ZodEnum<{
177
+ failed: "failed";
178
+ aborted: "aborted";
179
+ }>;
180
+ }, z.core.$loose>], "code">>;
181
+ }, z.core.$strict>], "state">;
77
182
  export declare const listJsonOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
78
183
  operator: z.ZodEnum<{
79
184
  message: "message";
@@ -175,6 +280,55 @@ export declare const listJsonOutputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
175
280
  path: z.ZodString;
176
281
  }, z.core.$loose>>;
177
282
  }, z.core.$loose>>;
283
+ selection: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
284
+ state: z.ZodLiteral<"resolvable">;
285
+ selectedCanonicalAgentId: z.ZodString;
286
+ }, z.core.$strict>, z.ZodObject<{
287
+ state: z.ZodLiteral<"unresolved">;
288
+ unresolvedReasons: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
289
+ code: z.ZodLiteral<"no_successful_verifiers">;
290
+ failedVerifierAgentIds: z.ZodArray<z.ZodString>;
291
+ }, z.core.$loose>, z.ZodObject<{
292
+ code: z.ZodLiteral<"verifier_failed">;
293
+ failedVerifierAgentIds: z.ZodArray<z.ZodString>;
294
+ }, z.core.$loose>, z.ZodObject<{
295
+ code: z.ZodLiteral<"verifier_preference_missing">;
296
+ verifierAgentId: z.ZodString;
297
+ }, z.core.$loose>, z.ZodObject<{
298
+ code: z.ZodLiteral<"verifier_preference_unresolved">;
299
+ verifierAgentId: z.ZodString;
300
+ preferredCandidateId: z.ZodOptional<z.ZodString>;
301
+ resolvedPreferredCandidateId: z.ZodOptional<z.ZodString>;
302
+ }, z.core.$loose>, z.ZodObject<{
303
+ code: z.ZodLiteral<"verifier_disagreement">;
304
+ selections: z.ZodArray<z.ZodObject<{
305
+ verifierAgentId: z.ZodString;
306
+ selectedCanonicalAgentId: z.ZodString;
307
+ }, z.core.$loose>>;
308
+ }, z.core.$loose>, z.ZodObject<{
309
+ code: z.ZodLiteral<"selector_unresolved">;
310
+ selector: z.ZodString;
311
+ availableCanonicalAgentIds: z.ZodArray<z.ZodString>;
312
+ availableAliases: z.ZodArray<z.ZodString>;
313
+ }, z.core.$loose>, z.ZodObject<{
314
+ code: z.ZodLiteral<"selector_ambiguous">;
315
+ selector: z.ZodString;
316
+ resolutions: z.ZodArray<z.ZodObject<{
317
+ sourceId: z.ZodString;
318
+ selectedCanonicalAgentId: z.ZodString;
319
+ }, z.core.$loose>>;
320
+ }, z.core.$loose>, z.ZodObject<{
321
+ code: z.ZodLiteral<"selected_candidate_failed_programmatic">;
322
+ selectedCanonicalAgentId: z.ZodString;
323
+ eligibleCanonicalAgentIds: z.ZodArray<z.ZodString>;
324
+ }, z.core.$loose>, z.ZodObject<{
325
+ code: z.ZodLiteral<"verification_not_succeeded">;
326
+ status: z.ZodEnum<{
327
+ failed: "failed";
328
+ aborted: "aborted";
329
+ }>;
330
+ }, z.core.$loose>], "code">>;
331
+ }, z.core.$strict>], "state">>;
178
332
  }, z.core.$loose>>;
179
333
  warnings: z.ZodArray<z.ZodString>;
180
334
  }, z.core.$loose>], "mode">;
@@ -66,6 +66,96 @@ const listJsonAgentSchema = z
66
66
  artifacts: z.array(listJsonArtifactSchema),
67
67
  })
68
68
  .passthrough();
69
+ const listJsonVerifierAgreementSelectionSchema = z
70
+ .object({
71
+ verifierAgentId: z.string(),
72
+ selectedCanonicalAgentId: z.string(),
73
+ })
74
+ .passthrough();
75
+ const listJsonSelectorResolutionMatchSchema = z
76
+ .object({
77
+ sourceId: z.string(),
78
+ selectedCanonicalAgentId: z.string(),
79
+ })
80
+ .passthrough();
81
+ export const listJsonVerificationSelectionUnresolvedReasonSchema = z.discriminatedUnion("code", [
82
+ z
83
+ .object({
84
+ code: z.literal("no_successful_verifiers"),
85
+ failedVerifierAgentIds: z.array(z.string()),
86
+ })
87
+ .passthrough(),
88
+ z
89
+ .object({
90
+ code: z.literal("verifier_failed"),
91
+ failedVerifierAgentIds: z.array(z.string()),
92
+ })
93
+ .passthrough(),
94
+ z
95
+ .object({
96
+ code: z.literal("verifier_preference_missing"),
97
+ verifierAgentId: z.string(),
98
+ })
99
+ .passthrough(),
100
+ z
101
+ .object({
102
+ code: z.literal("verifier_preference_unresolved"),
103
+ verifierAgentId: z.string(),
104
+ preferredCandidateId: z.string().optional(),
105
+ resolvedPreferredCandidateId: z.string().optional(),
106
+ })
107
+ .passthrough(),
108
+ z
109
+ .object({
110
+ code: z.literal("verifier_disagreement"),
111
+ selections: z.array(listJsonVerifierAgreementSelectionSchema),
112
+ })
113
+ .passthrough(),
114
+ z
115
+ .object({
116
+ code: z.literal("selector_unresolved"),
117
+ selector: z.string(),
118
+ availableCanonicalAgentIds: z.array(z.string()),
119
+ availableAliases: z.array(z.string()),
120
+ })
121
+ .passthrough(),
122
+ z
123
+ .object({
124
+ code: z.literal("selector_ambiguous"),
125
+ selector: z.string(),
126
+ resolutions: z.array(listJsonSelectorResolutionMatchSchema),
127
+ })
128
+ .passthrough(),
129
+ z
130
+ .object({
131
+ code: z.literal("selected_candidate_failed_programmatic"),
132
+ selectedCanonicalAgentId: z.string(),
133
+ eligibleCanonicalAgentIds: z.array(z.string()),
134
+ })
135
+ .passthrough(),
136
+ z
137
+ .object({
138
+ code: z.literal("verification_not_succeeded"),
139
+ status: z.enum(["failed", "aborted"]),
140
+ })
141
+ .passthrough(),
142
+ ]);
143
+ const listJsonResolvableVerificationSelectionSchema = z
144
+ .object({
145
+ state: z.literal("resolvable"),
146
+ selectedCanonicalAgentId: z.string(),
147
+ })
148
+ .strict();
149
+ const listJsonUnresolvedVerificationSelectionSchema = z
150
+ .object({
151
+ state: z.literal("unresolved"),
152
+ unresolvedReasons: z.array(listJsonVerificationSelectionUnresolvedReasonSchema),
153
+ })
154
+ .strict();
155
+ export const listJsonVerificationSelectionSchema = z.discriminatedUnion("state", [
156
+ listJsonResolvableVerificationSelectionSchema,
157
+ listJsonUnresolvedVerificationSelectionSchema,
158
+ ]);
69
159
  const listJsonDetailSessionSchema = listJsonSessionBaseSchema
70
160
  .extend({
71
161
  startedAt: z.string().optional(),
@@ -73,6 +163,7 @@ const listJsonDetailSessionSchema = listJsonSessionBaseSchema
73
163
  workspacePath: z.string(),
74
164
  description: z.string().nullable().optional(),
75
165
  agents: z.array(listJsonAgentSchema),
166
+ selection: listJsonVerificationSelectionSchema.optional(),
76
167
  })
77
168
  .passthrough();
78
169
  const listJsonSummaryOutputSchema = z
@@ -1,3 +1,3 @@
1
1
  import type { ToolAttachmentStatus } from "./model/types.js";
2
- export declare const FIRST_PARTY_ATTACHED_LAUNCH_PROMPT: "Voratiq MCP tools are attached to this repository: voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message, voratiq_list, and voratiq_apply. For Voratiq session history and workflow actions, prefer these tools over bash, search, or direct file reads. Read the guide resource at voratiq://guide for the full operator reference, workflow composition, and usage guidance.";
2
+ export declare const FIRST_PARTY_ATTACHED_LAUNCH_PROMPT: "Voratiq MCP tools are attached to this repository: voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message, voratiq_list, and voratiq_apply. Your role is to orchestrate Voratiq workflows for the user through these tools. Use Voratiq tools for workflow state and actions unless explicitly instructed otherwise, preserving sessions and apply outcomes instead of switching to local edits, replacement stages, or manual apply paths; read voratiq://guide for the operating contract, discipline rules, workflow composition, and operator reference.";
3
3
  export declare function resolveFirstPartyLaunchPrompt(toolAttachmentStatus: ToolAttachmentStatus): string | undefined;
@@ -1,4 +1,4 @@
1
- export const FIRST_PARTY_ATTACHED_LAUNCH_PROMPT = "Voratiq MCP tools are attached to this repository: voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message, voratiq_list, and voratiq_apply. For Voratiq session history and workflow actions, prefer these tools over bash, search, or direct file reads. Read the guide resource at voratiq://guide for the full operator reference, workflow composition, and usage guidance.";
1
+ export const FIRST_PARTY_ATTACHED_LAUNCH_PROMPT = "Voratiq MCP tools are attached to this repository: voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message, voratiq_list, and voratiq_apply. Your role is to orchestrate Voratiq workflows for the user through these tools. Use Voratiq tools for workflow state and actions unless explicitly instructed otherwise, preserving sessions and apply outcomes instead of switching to local edits, replacement stages, or manual apply paths; read voratiq://guide for the operating contract, discipline rules, workflow composition, and operator reference.";
2
2
  export function resolveFirstPartyLaunchPrompt(toolAttachmentStatus) {
3
3
  if (toolAttachmentStatus !== "attached") {
4
4
  return undefined;
@@ -42,6 +42,8 @@ export declare const messageRecipientEntrySchema: z.ZodObject<{
42
42
  output_tokens: z.ZodOptional<z.ZodNumber>;
43
43
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
44
44
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
45
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
46
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
45
47
  }, z.core.$strict>, z.ZodObject<{
46
48
  input_tokens: z.ZodOptional<z.ZodNumber>;
47
49
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -108,6 +110,8 @@ export declare const messageRecordSchema: z.ZodObject<{
108
110
  output_tokens: z.ZodOptional<z.ZodNumber>;
109
111
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
110
112
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
113
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
114
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
111
115
  }, z.core.$strict>, z.ZodObject<{
112
116
  input_tokens: z.ZodOptional<z.ZodNumber>;
113
117
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -39,6 +39,8 @@ export declare const reductionRecordReducerSchema: z.ZodObject<{
39
39
  output_tokens: z.ZodOptional<z.ZodNumber>;
40
40
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
41
41
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
42
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
43
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
42
44
  }, z.core.$strict>, z.ZodObject<{
43
45
  input_tokens: z.ZodOptional<z.ZodNumber>;
44
46
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -100,6 +102,8 @@ export declare const reductionRecordSchema: z.ZodObject<{
100
102
  output_tokens: z.ZodOptional<z.ZodNumber>;
101
103
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
102
104
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
105
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
106
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
103
107
  }, z.core.$strict>, z.ZodObject<{
104
108
  input_tokens: z.ZodOptional<z.ZodNumber>;
105
109
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -349,6 +349,8 @@ export declare const claudeExtractedTokenUsageSchema: z.ZodObject<{
349
349
  output_tokens: z.ZodOptional<z.ZodNumber>;
350
350
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
351
351
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
352
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
353
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
352
354
  }, z.core.$strict>;
353
355
  export type ClaudeExtractedTokenUsage = z.infer<typeof claudeExtractedTokenUsageSchema>;
354
356
  export declare const codexExtractedTokenUsageSchema: z.ZodObject<{
@@ -374,6 +376,8 @@ export declare const extractedTokenUsageSchemaByProvider: {
374
376
  output_tokens: z.ZodOptional<z.ZodNumber>;
375
377
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
376
378
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
379
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
380
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
377
381
  }, z.core.$strict>;
378
382
  readonly codex: z.ZodObject<{
379
383
  input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -396,6 +400,8 @@ export declare const extractedTokenUsageSchema: z.ZodUnion<readonly [z.ZodObject
396
400
  output_tokens: z.ZodOptional<z.ZodNumber>;
397
401
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
398
402
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
403
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
404
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
399
405
  }, z.core.$strict>, z.ZodObject<{
400
406
  input_tokens: z.ZodOptional<z.ZodNumber>;
401
407
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -459,6 +465,8 @@ export declare const agentInvocationRecordSchema: z.ZodObject<{
459
465
  output_tokens: z.ZodOptional<z.ZodNumber>;
460
466
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
461
467
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
468
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
469
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
462
470
  }, z.core.$strict>, z.ZodObject<{
463
471
  input_tokens: z.ZodOptional<z.ZodNumber>;
464
472
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -654,6 +662,8 @@ export declare const runRecordSchema: z.ZodObject<{
654
662
  output_tokens: z.ZodOptional<z.ZodNumber>;
655
663
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
656
664
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
665
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
666
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
657
667
  }, z.core.$strict>, z.ZodObject<{
658
668
  input_tokens: z.ZodOptional<z.ZodNumber>;
659
669
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -137,6 +137,8 @@ export const claudeExtractedTokenUsageSchema = withAtLeastOneUsageField({
137
137
  output_tokens: billingTokenCountSchema.optional(),
138
138
  cache_read_input_tokens: billingTokenCountSchema.optional(),
139
139
  cache_creation_input_tokens: billingTokenCountSchema.optional(),
140
+ cache_creation_ephemeral_5m_input_tokens: billingTokenCountSchema.optional(),
141
+ cache_creation_ephemeral_1h_input_tokens: billingTokenCountSchema.optional(),
140
142
  });
141
143
  export const codexExtractedTokenUsageSchema = withAtLeastOneUsageField({
142
144
  input_tokens: billingTokenCountSchema.optional(),
@@ -21,6 +21,8 @@ export declare const specAgentEntrySchema: z.ZodObject<{
21
21
  output_tokens: z.ZodOptional<z.ZodNumber>;
22
22
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
23
23
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
24
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
25
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
24
26
  }, z.core.$strict>, z.ZodObject<{
25
27
  input_tokens: z.ZodOptional<z.ZodNumber>;
26
28
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -74,6 +76,8 @@ export declare const specRecordSchema: z.ZodObject<{
74
76
  output_tokens: z.ZodOptional<z.ZodNumber>;
75
77
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
76
78
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
79
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
80
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
77
81
  }, z.core.$strict>, z.ZodObject<{
78
82
  input_tokens: z.ZodOptional<z.ZodNumber>;
79
83
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -98,6 +98,8 @@ export declare const verificationMethodResultRefSchema: z.ZodObject<{
98
98
  output_tokens: z.ZodOptional<z.ZodNumber>;
99
99
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
100
100
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
101
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
102
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
101
103
  }, z.core.$strict>, z.ZodObject<{
102
104
  input_tokens: z.ZodOptional<z.ZodNumber>;
103
105
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -368,6 +370,8 @@ export declare const verificationRecordSchema: z.ZodObject<{
368
370
  output_tokens: z.ZodOptional<z.ZodNumber>;
369
371
  cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
370
372
  cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
373
+ cache_creation_ephemeral_5m_input_tokens: z.ZodOptional<z.ZodNumber>;
374
+ cache_creation_ephemeral_1h_input_tokens: z.ZodOptional<z.ZodNumber>;
371
375
  }, z.core.$strict>, z.ZodObject<{
372
376
  input_tokens: z.ZodOptional<z.ZodNumber>;
373
377
  cached_input_tokens: z.ZodOptional<z.ZodNumber>;
@@ -144,8 +144,12 @@ function sanitizeGeminiArgs(agent) {
144
144
  index += 1;
145
145
  continue;
146
146
  }
147
- if (token === "--yolo") {
148
- continue;
147
+ if (token === "--approval-mode") {
148
+ const next = agent.argv[index + 1] ?? "";
149
+ if (next === "yolo") {
150
+ index += 1;
151
+ continue;
152
+ }
149
153
  }
150
154
  sanitized.push(token);
151
155
  }
@@ -69,7 +69,7 @@ const toolSpecs = [
69
69
  {
70
70
  name: "voratiq_run",
71
71
  operator: "run",
72
- description: "Execute a Voratiq spec session and create a run with agent outputs and artifacts.",
72
+ description: "Execute a Voratiq spec and create a recorded run session with agent outputs and artifacts.",
73
73
  inputSchemaSource: externalRunExecutionInputSchema,
74
74
  buildArgs: (input) => buildRunExecutionArgs(input),
75
75
  outputContract: "execution",
@@ -77,7 +77,7 @@ const toolSpecs = [
77
77
  {
78
78
  name: "voratiq_reduce",
79
79
  operator: "reduce",
80
- description: "Reduce a set of Voratiq artifacts into a summarized output for comparison or follow-on work.",
80
+ description: "Synthesize Voratiq artifacts into a reduced output for comparison or follow-on work.",
81
81
  inputSchemaSource: externalReduceExecutionInputSchema,
82
82
  buildArgs: (input) => buildReduceExecutionArgs(input),
83
83
  outputContract: "execution",
@@ -85,7 +85,7 @@ const toolSpecs = [
85
85
  {
86
86
  name: "voratiq_verify",
87
87
  operator: "verify",
88
- description: "Verify a Voratiq spec, run, reduction, or message session and record the evaluation result.",
88
+ description: "Evaluate a Voratiq spec, run, reduction, or message session and record a structured verdict.",
89
89
  inputSchemaSource: externalVerifyExecutionInputSchema,
90
90
  buildArgs: (input) => buildVerifyExecutionArgs(input),
91
91
  outputContract: "execution",
@@ -101,7 +101,7 @@ const toolSpecs = [
101
101
  {
102
102
  name: "voratiq_apply",
103
103
  operator: "apply",
104
- description: "Apply an accepted Voratiq run diff into the current working tree.",
104
+ description: "Apply an accepted Voratiq run diff into the current working tree and record applyStatus.",
105
105
  inputSchemaSource: externalApplyExecutionInputSchema,
106
106
  buildArgs: (input) => buildApplyExecutionArgs(input),
107
107
  outputContract: "execution",
@@ -109,7 +109,7 @@ const toolSpecs = [
109
109
  {
110
110
  name: "voratiq_list",
111
111
  operator: "list",
112
- description: "Inspect recorded Voratiq sessions for one operator (`spec`, `run`, `reduce`, `verify`, `message`, or `interactive`) in summary or detail scope.",
112
+ description: "Inspect or poll recorded Voratiq sessions for one operator (`spec`, `run`, `reduce`, `verify`, `message`, or `interactive`) in summary or detail scope.",
113
113
  inputSchemaSource: mcpListInspectionInputSchema,
114
114
  mcpInputSchema: createListMcpInputSchema(),
115
115
  buildArgs: (input) => buildListInspectionArgs(input),
@@ -124,65 +124,70 @@ const toolDefinitions = toolSpecs.map((tool) => ({
124
124
  export const VORATIQ_GUIDE_RESOURCE_URI = "voratiq://guide";
125
125
  const VORATIQ_GUIDE_RESOURCE_CONTENT = `# Voratiq Operator Guide
126
126
 
127
- Voratiq is a workflow system built around composable operators that launch, evaluate, and manage multi-agent work against a repository. It gives interactive agents a structured way to delegate coding tasks, inspect recorded state, verify outcomes, and apply accepted changes without doing all of that inline.
127
+ ## Operating Contract
128
128
 
129
- ## Operator Classes
129
+ Voratiq is a stateful workflow control plane for multi-agent work in a repository. Its records connect session state, verification decisions, artifacts, orchestration choices, and accepted work across stages.
130
130
 
131
- Voratiq operators fall into two main classes:
131
+ Your role is to orchestrate Voratiq workflows for the user through Voratiq tools. This means using Voratiq tools for workflow state and actions and preserving sessions and apply outcomes.
132
132
 
133
- - **Swarm operators** dispatch agents to produce, synthesize, or evaluate work: spec, run, reduce, verify, message
134
- - **Control operators** inspect state or mutate accepted outcomes: apply, list
133
+ - **Voratiq state is authoritative.** Sessions, verifier decisions, reductions, unresolved outcomes, and apply records are durable workflow state. A terminal session status means a stage stopped; the recorded output still needs interpretation before the next stage.
134
+ - **Orchestration controls define meaning.** **agentIds**, **profile**, and **maxParallel** shape which swarm produced the result and how that result should be understood.
135
+ - **Artifacts carry lineage.** Artifact paths are workflow outputs with a producing operator, role, and surrounding decision state. The producing context determines whether an artifact is suitable input for another operator.
136
+ - **Apply through Voratiq.** **voratiq_apply** materializes an accepted run candidate and records **applyStatus**, including which agent result was accepted.
135
137
 
136
- ## Swarm Operators
138
+ ## Discipline Rules
137
139
 
138
- **spec** Drafts or refines a specification for a task from a description, an existing spec, or related repository context. Launches one or more spec agents and records their outputs as a spec session.
140
+ Unless explicitly instructed otherwise:
139
141
 
140
- **run** Executes a spec session by launching run agents that read the spec, work against a sandboxed workspace, and produce artifacts including diffs and transcripts. Records a run session.
142
+ - **Keep workflow actions in Voratiq.** Do not edit repository files, manually patch diffs, cherry-pick, or materialize changes outside the recorded run/apply path while a Voratiq workflow is active.
143
+ - **Respect stage boundaries.** Do not advance from spec to run, run to apply, or unresolved verification to rerun/apply until the relevant session state is terminal and understood; use **voratiq_list** and bring unresolved decisions back to the user.
144
+ - **Do not duplicate active swarm work.** If a spec, run, reduce, verify, or message session is queued or running, poll it with **voratiq_list** instead of launching a replacement because it is slow or unclear.
145
+ - **Leave orchestration controls unset by default.** Do not pass **agentIds**, **profile**, or **maxParallel** unless the user explicitly asks for them. **maxParallel** limits concurrency; it does not choose a smaller swarm.
146
+ - **Apply accepted runs through Voratiq.** Use **voratiq_apply** so **applyStatus** records the accepted agent. Surface conflicts, dirty state, or base mismatch instead of bypassing apply.
141
147
 
142
- **reduce** – Summarizes artifacts from a spec, run, or message session into a single reduced output suitable for comparison or follow-on work. Records a reduce session.
148
+ ## Operators
143
149
 
144
- **verify** Evaluates a spec, run, reduction, or message session and records a structured verdict. This is Voratiq's main decision operator: use it to compare outputs, choose stronger candidates, and decide whether work should be applied, inspected further, rerun, or redirected.
150
+ Swarm operators create recorded sessions and may acknowledge before finishing:
145
151
 
146
- **message** Sends an isolated prompt to one or more agents and persists each reply independently as a message session. Use for standalone questions, reviews, or exploration that does not require a full spec/run workflow.
152
+ - **spec** drafts or refines a task specification.
153
+ - **run** executes a spec and records agent outputs, diffs, and transcripts.
154
+ - **reduce** synthesizes artifacts from a spec, run, verify, or message session for comparison or follow-on work.
155
+ - **verify** records a structured verdict over a spec, run, reduction, or message session.
156
+ - **message** sends an isolated prompt to agents and records independent replies.
147
157
 
148
- ## Control Operators
158
+ Control operators inspect or materialize recorded state:
149
159
 
150
- **list** – Lists or inspects recorded sessions for a given operator. This is the primary way to inspect swarm sessions; use it to poll progress, retrieve session IDs, and inspect recorded workflow state.
151
-
152
- **apply** – Applies an accepted run diff into the current working tree. Synchronous and non-durable; only invoke after verifying that the target run is in an acceptable state.
160
+ - **list** is the primary control plane for session history, progress polling, and detail inspection.
161
+ - **apply** materializes an accepted run diff into the working tree and records the apply outcome.
153
162
 
154
163
  ## Workflow Composition
155
164
 
156
- Operators compose into many workflow shapes rather than one required path. Common patterns include: using message for standalone exploration or review; using spec verify to compare candidate specs before execution; using spec run when a task needs structured execution; using run verify to choose among competing implementations; using reduce when multiple outputs need synthesis before a decision; and using verify whenever a workflow needs a structured recommendation instead of ad hoc judgment. The list operator can be called at any point to inspect recorded state across all operators.
157
-
158
- ## Swarm Session Behavior
165
+ Operators compose into different workflow shapes. Use **message** for standalone exploration, **spec -> verify** to compare candidate specs, **spec -> run** for structured execution, **run -> verify** to choose among implementations, and **reduce** when several artifacts need synthesis before a decision. A typical accepted-change path is **spec -> verify -> run -> verify -> apply**.
159
166
 
160
- The five swarm operators are spec, run, reduce, verify, and message. Each one creates a recorded session and may return before the session is finished. Once a session has been created, treat that session as the unit of work. A returned sessionId means the work has been launched, not completed. Use voratiq_list to inspect active sessions.
167
+ Keep one workflow objective per sequence. Before moving to the next stage, inspect the recorded state with **voratiq_list**. Queued, running, timed-out, or unclear sessions are normally handled by polling the recorded session; launching another swarm stage creates a separate workflow event.
161
168
 
162
- ## Status Interpretation
169
+ ## Sessions, Status, and Polling
163
170
 
164
- Session status is primary; recipient status is supporting detail.
171
+ The session is the unit of work. A returned **sessionId** means work was launched, not completed. **queued** and **running** are expected latency states. Mixed recipient states are supporting detail and do not override session status.
165
172
 
166
- - **queued** means the session has been accepted and recorded but its work has not started yet.
167
- - **running** means the session is active and remains the canonical in-flight unit of work.
168
- - **succeeded** means the session reached a successful terminal state; inspect its outputs and decide what should happen next.
169
- - **failed** means the session reached a terminal failure state.
170
- - **unresolved** means the session reached a terminal state without a clear winner or confident decision.
173
+ Terminal statuses still require interpretation:
171
174
 
172
- Mixed recipient states do not imply session failure. Some recipients may fail while others continue running, and the session remains active until its session status becomes terminal.
175
+ - **succeeded** means the operator produced its recorded output; inspect it in context before acting.
176
+ - **failed** means the stage ended in failure.
177
+ - **unresolved** means verification or selection ended without a clear winner or confident decision; review the evidence and decide the next step from that recorded state.
173
178
 
174
- ## extraContext Contract
179
+ Advance only after the verification state you depend on is terminal and understood.
175
180
 
176
- The extraContext field accepts an array of file paths pointing to additional readable files staged alongside the operator workspace. Pass file paths only — not raw text content, and not paths to files that operators already see by default (such as standard repository context). Passing raw content or redundant paths increases token usage without providing new information.
181
+ ## Lineage and Inputs
177
182
 
178
- ## maxParallel Semantics
183
+ Treat artifact paths as typed workflow inputs. **run** expects a spec input. **reduce** and **verify** evaluate recorded sessions or artifacts in their producing context. A reduction can summarize evidence for follow-on work, but its role still matters when carrying it into another operator.
179
184
 
180
- The maxParallel field controls the maximum number of agent recipients running in parallel for an operator invocation. Set it deliberately: it directly affects cost and latency. Higher values increase concurrency but also increase total token expenditure and can create contention. Do not treat maxParallel as a free dial to increase throughput without modeling the downstream cost and latency impact.
185
+ The **extraContext** field accepts file paths to additional readable files staged beside the operator workspace. Pass paths only, not raw text, and avoid files the operator already receives by default.
181
186
 
182
- ## Key Discipline Rules
187
+ ## Orchestration Controls
183
188
 
184
- Commit to one workflow objective per session; do not interleave unrelated operator calls in the same sequence. Wait for stage boundaries before acting on results: read voratiq_list output before proceeding from one stage to the next. Use voratiq_list as the primary control plane for inspecting recorded state rather than reading session files directly.`;
185
- const VORATIQ_MCP_SERVER_INSTRUCTIONS = "Voratiq tools operate on Voratiq workflow state in the current repository. Use voratiq_list for questions about recent or specific spec, run, reduce, verify, message, or interactive sessions. The swarm operators (voratiq_spec, voratiq_run, voratiq_reduce, voratiq_verify, voratiq_message) create recorded sessions and may acknowledge before finishing; once launched, treat the session as the unit of work. If a swarm call times out or returns a non-terminal status, inspect progress with voratiq_list instead of retrying. Use voratiq_apply for synchronous control actions. Prefer these tools over shell inspection when the task is about Voratiq workflow history or state.";
189
+ **agentIds**, **profile**, and **maxParallel** are semantic inputs. They determine which agents are compared and how the swarm result should be read. Use them when intentionally selecting participants, a profile, or concurrency. **maxParallel** also affects cost, latency, and contention, so set it deliberately.`;
190
+ const VORATIQ_MCP_SERVER_INSTRUCTIONS = "Voratiq MCP tools operate on durable workflow state. Your role is to orchestrate Voratiq workflows for the user through Voratiq MCP tools. Use voratiq_list to inspect and poll sessions. Unless explicitly instructed otherwise: keep workflow actions in Voratiq; wait for terminal stage state and bring unresolved decisions back to the user; do not launch replacement stages for queued/running work; do not pass agentIds, profile, or maxParallel without an explicit user request; use voratiq_apply for accepted runs so applyStatus records the accepted agent, and surface blockers instead of bypassing. Read voratiq://guide for the full contract.";
186
191
  const toolSpecsByName = new Map(toolSpecs.map((tool) => [tool.name, tool]));
187
192
  export function getVoratiqMcpToolDefinitions() {
188
193
  return toolDefinitions;
@@ -267,7 +272,7 @@ export function createVoratiqMcpRequestHandler(options = {}) {
267
272
  {
268
273
  uri: VORATIQ_GUIDE_RESOURCE_URI,
269
274
  name: "Voratiq Operator Guide",
270
- description: "Complete reference for Voratiq operators, workflow composition, swarm-session behavior, extraContext contract, and maxParallel semantics.",
275
+ description: "Operating contract and reference for Voratiq state, orchestration controls, artifact lineage, operators, polling, and apply attribution.",
271
276
  mimeType: "text/plain",
272
277
  },
273
278
  ],
@@ -18,7 +18,7 @@ interface ExtractClaudeChatUsageFromJsonlOptions {
18
18
  content: string;
19
19
  modelId: string;
20
20
  }
21
- interface ExtractGeminiChatUsageFromJsonOptions {
21
+ interface ExtractGeminiChatUsageFromJsonlOptions {
22
22
  artifactPath: string;
23
23
  content: string;
24
24
  modelId: string;
@@ -26,5 +26,5 @@ interface ExtractGeminiChatUsageFromJsonOptions {
26
26
  export declare function extractChatUsageFromArtifact(options: ExtractChatUsageArtifactOptions): Promise<ChatUsageExtractionResult>;
27
27
  export declare function extractCodexChatUsageFromJsonl(options: ExtractCodexChatUsageFromJsonlOptions): ChatUsageExtractionResult;
28
28
  export declare function extractClaudeChatUsageFromJsonl(options: ExtractClaudeChatUsageFromJsonlOptions): ChatUsageExtractionResult;
29
- export declare function extractGeminiChatUsageFromJson(options: ExtractGeminiChatUsageFromJsonOptions): ChatUsageExtractionResult;
29
+ export declare function extractGeminiChatUsageFromJsonl(options: ExtractGeminiChatUsageFromJsonlOptions): ChatUsageExtractionResult;
30
30
  export {};
@@ -38,7 +38,7 @@ export async function extractChatUsageFromArtifact(options) {
38
38
  message: `Usage extraction is not implemented for provider \`${providerId}\` yet.`,
39
39
  });
40
40
  }
41
- if (format !== providerShape.artifactFormat) {
41
+ if (!isProviderArtifactFormatSupported(providerId, format)) {
42
42
  const providerLabel = formatProviderLabel(providerId);
43
43
  return buildUnavailableResult({
44
44
  reason: "unsupported_provider",
@@ -63,7 +63,7 @@ export async function extractChatUsageFromArtifact(options) {
63
63
  modelId,
64
64
  });
65
65
  case "gemini":
66
- return extractGeminiChatUsageFromJson({
66
+ return extractGeminiChatUsageFromJsonl({
67
67
  artifactPath,
68
68
  content,
69
69
  modelId,
@@ -110,16 +110,6 @@ export function extractCodexChatUsageFromJsonl(options) {
110
110
  });
111
111
  }
112
112
  const latestTokenCountEvent = tokenCountEvents.at(-1);
113
- if (!latestTokenCountEvent) {
114
- return buildUnavailableResult({
115
- reason: "missing",
116
- artifactPath,
117
- format: "jsonl",
118
- providerId: "codex",
119
- modelId,
120
- message: "No Codex token_count usage events were found in chat.jsonl.",
121
- });
122
- }
123
113
  const totalTokenUsage = asRecord(latestTokenCountEvent.info.total_token_usage);
124
114
  if (!totalTokenUsage) {
125
115
  return buildUnavailableResult({
@@ -193,7 +183,14 @@ export function extractClaudeChatUsageFromJsonl(options) {
193
183
  });
194
184
  }
195
185
  const normalizedUsage = [];
186
+ const seenResponseKeys = new Set();
196
187
  for (const usageMessage of usageMessages) {
188
+ if (usageMessage.responseKey) {
189
+ if (seenResponseKeys.has(usageMessage.responseKey)) {
190
+ continue;
191
+ }
192
+ seenResponseKeys.add(usageMessage.responseKey);
193
+ }
197
194
  const usageRecord = asRecord(usageMessage.usage);
198
195
  if (!usageRecord) {
199
196
  return buildUnavailableResult({
@@ -241,44 +238,69 @@ export function extractClaudeChatUsageFromJsonl(options) {
241
238
  tokenUsage: usage,
242
239
  };
243
240
  }
244
- export function extractGeminiChatUsageFromJson(options) {
241
+ export function extractGeminiChatUsageFromJsonl(options) {
245
242
  const { artifactPath, content, modelId } = options;
246
- let parsedRoot;
247
- try {
248
- parsedRoot = JSON.parse(content);
249
- }
250
- catch (error) {
251
- return buildUnavailableResult({
252
- reason: "malformed",
253
- artifactPath,
254
- format: "json",
255
- providerId: "gemini",
256
- modelId,
257
- message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
258
- });
259
- }
260
- const root = asRecord(parsedRoot);
261
- if (!root) {
262
- return buildUnavailableResult({
263
- reason: "malformed",
264
- artifactPath,
265
- format: "json",
266
- providerId: "gemini",
267
- modelId,
268
- message: "Gemini chat artifact must be a JSON object.",
269
- });
243
+ const tokensPayloadsByResponseId = new Map();
244
+ const tokensPayloadsWithoutResponseId = [];
245
+ const lines = content.split(/\r?\n/u);
246
+ for (const [index, rawLine] of lines.entries()) {
247
+ const trimmed = rawLine.trim();
248
+ if (trimmed.length === 0) {
249
+ continue;
250
+ }
251
+ let parsedLine;
252
+ try {
253
+ parsedLine = JSON.parse(trimmed);
254
+ }
255
+ catch (error) {
256
+ return buildUnavailableResult({
257
+ reason: "malformed",
258
+ artifactPath,
259
+ format: "jsonl",
260
+ providerId: "gemini",
261
+ modelId,
262
+ message: `Invalid JSONL at line ${index + 1}: ${error instanceof Error ? error.message : String(error)}`,
263
+ });
264
+ }
265
+ const root = asRecord(parsedLine);
266
+ if (!root || !("tokens" in root)) {
267
+ continue;
268
+ }
269
+ const tokensPayload = {
270
+ location: `line ${index + 1}.tokens`,
271
+ tokens: root.tokens,
272
+ };
273
+ const responseId = typeof root.id === "string" ? root.id.trim() : "";
274
+ if (responseId.length > 0) {
275
+ tokensPayloadsByResponseId.set(responseId, tokensPayload);
276
+ }
277
+ else {
278
+ tokensPayloadsWithoutResponseId.push(tokensPayload);
279
+ }
270
280
  }
271
- const tokensPayloads = parseGeminiTokensPayloads(root);
281
+ const tokensPayloads = [
282
+ ...tokensPayloadsWithoutResponseId,
283
+ ...tokensPayloadsByResponseId.values(),
284
+ ];
272
285
  if (tokensPayloads.length === 0) {
273
286
  return buildUnavailableResult({
274
287
  reason: "missing",
275
288
  artifactPath,
276
- format: "json",
289
+ format: "jsonl",
277
290
  providerId: "gemini",
278
291
  modelId,
279
- message: "No Gemini tokens payloads were found in chat.json.",
292
+ message: "No Gemini tokens payloads were found in chat.jsonl.",
280
293
  });
281
294
  }
295
+ return extractGeminiTokenUsageFromPayloads({
296
+ artifactPath,
297
+ format: "jsonl",
298
+ modelId,
299
+ tokensPayloads,
300
+ });
301
+ }
302
+ function extractGeminiTokenUsageFromPayloads(options) {
303
+ const { artifactPath, format, modelId, tokensPayloads } = options;
282
304
  const normalizedUsage = [];
283
305
  for (const tokensPayload of tokensPayloads) {
284
306
  const tokensRecord = asRecord(tokensPayload.tokens);
@@ -286,7 +308,7 @@ export function extractGeminiChatUsageFromJson(options) {
286
308
  return buildUnavailableResult({
287
309
  reason: "malformed",
288
310
  artifactPath,
289
- format: "json",
311
+ format,
290
312
  providerId: "gemini",
291
313
  modelId,
292
314
  message: `Gemini ${tokensPayload.location} is not an object.`,
@@ -300,7 +322,7 @@ export function extractGeminiChatUsageFromJson(options) {
300
322
  return buildUnavailableResult({
301
323
  reason: "malformed",
302
324
  artifactPath,
303
- format: "json",
325
+ format,
304
326
  providerId: "gemini",
305
327
  modelId,
306
328
  message: `Gemini ${tokensPayload.location} did not contain any valid token usage fields.`,
@@ -313,7 +335,7 @@ export function extractGeminiChatUsageFromJson(options) {
313
335
  return buildUnavailableResult({
314
336
  reason: "malformed",
315
337
  artifactPath,
316
- format: "json",
338
+ format,
317
339
  providerId: "gemini",
318
340
  modelId,
319
341
  message: "Gemini tokens payloads did not contain any valid token usage fields.",
@@ -323,7 +345,7 @@ export function extractGeminiChatUsageFromJson(options) {
323
345
  status: "available",
324
346
  provider: "gemini",
325
347
  artifactPath,
326
- format: "json",
348
+ format,
327
349
  modelId,
328
350
  tokenUsage: usage,
329
351
  };
@@ -342,24 +364,6 @@ function buildUnavailableResult(options) {
342
364
  }
343
365
  function parseCodexTokenCountEvent(value) {
344
366
  const root = asRecord(value);
345
- const eventMsg = parseCodexEnvelope(root);
346
- if (eventMsg) {
347
- const info = asRecord(eventMsg.info);
348
- if (info) {
349
- return { info };
350
- }
351
- }
352
- const legacyEventMsg = asRecord(root?.event_msg);
353
- if (legacyEventMsg?.type !== "token_count") {
354
- return undefined;
355
- }
356
- const info = asRecord(legacyEventMsg.info);
357
- if (!info) {
358
- return undefined;
359
- }
360
- return { info };
361
- }
362
- function parseCodexEnvelope(root) {
363
367
  if (root?.type !== "event_msg") {
364
368
  return undefined;
365
369
  }
@@ -367,59 +371,37 @@ function parseCodexEnvelope(root) {
367
371
  if (payload?.type !== "token_count") {
368
372
  return undefined;
369
373
  }
370
- return payload;
374
+ const info = asRecord(payload.info);
375
+ if (!info) {
376
+ return undefined;
377
+ }
378
+ return { info };
371
379
  }
372
380
  function parseClaudeUsageMessage(value, lineNumber) {
373
381
  const root = asRecord(value);
374
382
  const message = asRecord(root?.message);
375
- if (!message || !("usage" in message)) {
383
+ if (!root || !message || !("usage" in message)) {
376
384
  return undefined;
377
385
  }
378
386
  return {
379
387
  lineNumber,
388
+ responseKey: buildClaudeResponseKey(root, message),
380
389
  usage: message.usage,
381
390
  };
382
391
  }
383
- function parseGeminiTokensPayloads(root) {
384
- const tokensPayloads = [];
385
- if ("tokens" in root) {
386
- tokensPayloads.push({
387
- location: "tokens",
388
- tokens: root.tokens,
389
- });
390
- }
391
- if ("transcripts" in root) {
392
- if (!Array.isArray(root.transcripts)) {
393
- return [{ location: "transcripts", tokens: undefined }];
394
- }
395
- for (const [index, transcript] of root.transcripts.entries()) {
396
- const transcriptRecord = asRecord(transcript);
397
- const payload = asRecord(transcriptRecord?.payload);
398
- if (!payload) {
399
- continue;
400
- }
401
- if ("tokens" in payload) {
402
- tokensPayloads.push({
403
- location: `transcripts[${index}].payload.tokens`,
404
- tokens: payload.tokens,
405
- });
406
- }
407
- if (!Array.isArray(payload.messages)) {
408
- continue;
409
- }
410
- for (const [messageIndex, message] of payload.messages.entries()) {
411
- const messageRecord = asRecord(message);
412
- if (!messageRecord || !("tokens" in messageRecord)) {
413
- continue;
414
- }
415
- tokensPayloads.push({
416
- location: `transcripts[${index}].payload.messages[${messageIndex}].tokens`,
417
- tokens: messageRecord.tokens,
418
- });
419
- }
420
- }
392
+ function buildClaudeResponseKey(root, message) {
393
+ const messageId = typeof message.id === "string" ? message.id.trim() : "";
394
+ if (messageId.length === 0) {
395
+ return undefined;
421
396
  }
422
- return tokensPayloads;
397
+ const requestId = typeof root.requestId === "string" ? root.requestId.trim() : "";
398
+ return requestId.length > 0
399
+ ? `request:${requestId}:message:${messageId}`
400
+ : `message:${messageId}`;
401
+ }
402
+ function isProviderArtifactFormatSupported(providerId, format) {
403
+ const providerShape = PROVIDER_USAGE_SHAPE_MAPPINGS[providerId];
404
+ return format === providerShape.artifactFormat;
423
405
  }
424
406
  function formatProviderLabel(providerId) {
425
407
  switch (providerId) {
@@ -2,6 +2,7 @@ import { type ChatUsageProviderId, type ExtractedTokenUsage } from "../../domain
2
2
  import type { ChatArtifactFormat } from "./types.js";
3
3
  export interface ProviderUsageFieldMapping {
4
4
  artifactFieldPath: string;
5
+ usagePayloadFieldPath?: string;
5
6
  usageFieldPath: string;
6
7
  }
7
8
  export interface ProviderUsageShapeMapping {
@@ -22,40 +22,50 @@ export const PROVIDER_USAGE_SHAPE_MAPPINGS = {
22
22
  artifactFieldPath: "usage.cache_creation_input_tokens",
23
23
  usageFieldPath: "cache_creation_input_tokens",
24
24
  },
25
+ {
26
+ artifactFieldPath: "usage.cache_creation.ephemeral_5m_input_tokens",
27
+ usagePayloadFieldPath: "cache_creation.ephemeral_5m_input_tokens",
28
+ usageFieldPath: "cache_creation_ephemeral_5m_input_tokens",
29
+ },
30
+ {
31
+ artifactFieldPath: "usage.cache_creation.ephemeral_1h_input_tokens",
32
+ usagePayloadFieldPath: "cache_creation.ephemeral_1h_input_tokens",
33
+ usageFieldPath: "cache_creation_ephemeral_1h_input_tokens",
34
+ },
25
35
  ],
26
36
  },
27
37
  codex: {
28
38
  providerId: "codex",
29
39
  artifactFormat: "jsonl",
30
- artifactShape: "event_msg(type=token_count).info.total_token_usage",
31
- usageRootPath: "event_msg.info.total_token_usage",
40
+ artifactShape: "event_msg(type=token_count).payload.info.total_token_usage",
41
+ usageRootPath: "payload.info.total_token_usage",
32
42
  billingRelevantFields: [
33
43
  {
34
- artifactFieldPath: "event_msg.info.total_token_usage.input_tokens",
44
+ artifactFieldPath: "payload.info.total_token_usage.input_tokens",
35
45
  usageFieldPath: "input_tokens",
36
46
  },
37
47
  {
38
- artifactFieldPath: "event_msg.info.total_token_usage.cached_input_tokens",
48
+ artifactFieldPath: "payload.info.total_token_usage.cached_input_tokens",
39
49
  usageFieldPath: "cached_input_tokens",
40
50
  },
41
51
  {
42
- artifactFieldPath: "event_msg.info.total_token_usage.output_tokens",
52
+ artifactFieldPath: "payload.info.total_token_usage.output_tokens",
43
53
  usageFieldPath: "output_tokens",
44
54
  },
45
55
  {
46
- artifactFieldPath: "event_msg.info.total_token_usage.reasoning_output_tokens",
56
+ artifactFieldPath: "payload.info.total_token_usage.reasoning_output_tokens",
47
57
  usageFieldPath: "reasoning_output_tokens",
48
58
  },
49
59
  {
50
- artifactFieldPath: "event_msg.info.total_token_usage.total_tokens",
60
+ artifactFieldPath: "payload.info.total_token_usage.total_tokens",
51
61
  usageFieldPath: "total_tokens",
52
62
  },
53
63
  ],
54
64
  },
55
65
  gemini: {
56
66
  providerId: "gemini",
57
- artifactFormat: "json",
58
- artifactShape: "transcript.tokens",
67
+ artifactFormat: "jsonl",
68
+ artifactShape: "jsonl row tokens",
59
69
  usageRootPath: "tokens",
60
70
  billingRelevantFields: [
61
71
  {
@@ -93,7 +103,7 @@ export function extractObservedProviderNativeUsage(options) {
93
103
  }
94
104
  const nativeUsage = {};
95
105
  for (const fieldMapping of mapping.billingRelevantFields) {
96
- const value = getPathValue(usageRecord, fieldMapping.usageFieldPath);
106
+ const value = getPathValue(usageRecord, fieldMapping.usagePayloadFieldPath ?? fieldMapping.usageFieldPath) ?? getPathValue(usageRecord, fieldMapping.usageFieldPath);
97
107
  const tokenCount = normalizeTokenCount(value);
98
108
  if (tokenCount !== undefined) {
99
109
  nativeUsage[fieldMapping.usageFieldPath] = tokenCount;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "voratiq",
3
- "version": "0.1.0-beta.25",
3
+ "version": "0.1.0-beta.26",
4
4
  "description": "Run workflows, delegate to swarms, and verify outputs before you apply them.",
5
5
  "keywords": [
6
6
  "agent-ensembles",