@dudousxd/nestjs-agent-core 0.39.0 → 0.41.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 +7 -0
- package/dist/ag-ui/index.cjs +123 -9
- package/dist/ag-ui/index.cjs.map +1 -1
- package/dist/ag-ui/index.d.cts +19 -3
- package/dist/ag-ui/index.d.ts +19 -3
- package/dist/ag-ui/index.js +122 -9
- package/dist/ag-ui/index.js.map +1 -1
- package/dist/{catalog-CrzetM3_.d.cts → catalog-BKS3Yxo6.d.cts} +2 -0
- package/dist/{catalog-CrzetM3_.d.ts → catalog-BKS3Yxo6.d.ts} +2 -0
- package/dist/genui/builtins.cjs +2 -0
- package/dist/genui/builtins.cjs.map +1 -1
- package/dist/genui/builtins.d.cts +1 -1
- package/dist/genui/builtins.d.ts +1 -1
- package/dist/genui/builtins.js +2 -0
- package/dist/genui/builtins.js.map +1 -1
- package/dist/genui/index.cjs +780 -106
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.d.cts +5 -5
- package/dist/genui/index.d.ts +5 -5
- package/dist/genui/index.js +770 -105
- package/dist/genui/index.js.map +1 -1
- package/dist/guardrails/index.cjs +3 -1
- package/dist/guardrails/index.cjs.map +1 -1
- package/dist/guardrails/index.d.cts +5 -4
- package/dist/guardrails/index.d.ts +5 -4
- package/dist/guardrails/index.js +3 -1
- package/dist/guardrails/index.js.map +1 -1
- package/dist/index.cjs +3324 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +388 -96
- package/dist/index.d.ts +388 -96
- package/dist/index.js +3279 -377
- package/dist/index.js.map +1 -1
- package/dist/{processors-6p9nrqEi.d.cts → processors-BXM-MNga.d.cts} +1 -1
- package/dist/{processors-Bp5XmF6V.d.ts → processors-ByDr5POu.d.ts} +1 -1
- package/dist/{stream-events-CbVEowYb.d.cts → stream-events-BGKLD6RX.d.ts} +664 -86
- package/dist/{stream-events-CbVEowYb.d.ts → stream-events-CF-6-Y6L.d.cts} +664 -86
- package/package.json +1 -1
- package/dist/tool-DZYLEKnl.d.cts +0 -121
- package/dist/tool-_iq4xRyk.d.ts +0 -121
package/dist/index.cjs
CHANGED
|
@@ -53,6 +53,8 @@ __export(src_exports, {
|
|
|
53
53
|
APPROVAL_EXPIRED_REASON: () => APPROVAL_EXPIRED_REASON,
|
|
54
54
|
ASK_TOOL_DESCRIPTION: () => ASK_TOOL_DESCRIPTION,
|
|
55
55
|
ASK_TOOL_NAME: () => ASK_TOOL_NAME,
|
|
56
|
+
ActionProposalExecutor: () => ActionProposalExecutor,
|
|
57
|
+
ActionProposalWorker: () => ActionProposalWorker,
|
|
56
58
|
AgentRegistry: () => AgentRegistry,
|
|
57
59
|
AgentStreamError: () => AgentStreamError,
|
|
58
60
|
CONFIRM_JSON_SCHEMA_PROPERTIES: () => CONFIRM_JSON_SCHEMA_PROPERTIES,
|
|
@@ -67,12 +69,15 @@ __export(src_exports, {
|
|
|
67
69
|
DEFAULT_MAX_SKILLS: () => DEFAULT_MAX_SKILLS,
|
|
68
70
|
DEFAULT_REFUSAL_REASON: () => DEFAULT_REFUSAL_REASON,
|
|
69
71
|
DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION: () => DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
|
|
72
|
+
DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES: () => DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES,
|
|
73
|
+
DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY: () => DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY,
|
|
70
74
|
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS: () => DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
71
75
|
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS: () => DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
72
76
|
DefaultApprovalPolicy: () => DefaultApprovalPolicy,
|
|
73
77
|
DefaultRolesPolicy: () => DefaultRolesPolicy,
|
|
74
78
|
ELICITATION_INPUT_TYPES: () => ELICITATION_INPUT_TYPES,
|
|
75
79
|
GLOBAL_SCOPE: () => GLOBAL_SCOPE,
|
|
80
|
+
InMemoryActionProposalStore: () => InMemoryActionProposalStore,
|
|
76
81
|
InMemoryAgentStore: () => InMemoryAgentStore,
|
|
77
82
|
InMemoryConfirmTokenStore: () => InMemoryConfirmTokenStore,
|
|
78
83
|
MAX_ASK_QUESTIONS: () => MAX_ASK_QUESTIONS,
|
|
@@ -96,15 +101,25 @@ __export(src_exports, {
|
|
|
96
101
|
THREAD_DETAIL_CONTENT_CHARS: () => THREAD_DETAIL_CONTENT_CHARS,
|
|
97
102
|
ToolDisabledError: () => ToolDisabledError,
|
|
98
103
|
ToolForbiddenError: () => ToolForbiddenError,
|
|
104
|
+
ToolInputDriftError: () => ToolInputDriftError,
|
|
99
105
|
ToolInputInvalidError: () => ToolInputInvalidError,
|
|
100
106
|
ToolNotFoundError: () => ToolNotFoundError,
|
|
107
|
+
ToolPreflightDeniedError: () => ToolPreflightDeniedError,
|
|
101
108
|
ToolRegistry: () => ToolRegistry,
|
|
102
109
|
UNFINISHED_TOOL_CALL: () => UNFINISHED_TOOL_CALL,
|
|
110
|
+
actionProposalCreationMatches: () => actionProposalCreationMatches,
|
|
111
|
+
actionProposalOutcomeFenceValid: () => actionProposalOutcomeFenceValid,
|
|
112
|
+
actionProposalOutcomeScope: () => actionProposalOutcomeScope,
|
|
113
|
+
actionProposalOutcomeText: () => actionProposalOutcomeText,
|
|
114
|
+
actionProposalReceipt: () => actionProposalReceipt,
|
|
115
|
+
actionProposalScopeMatches: () => actionProposalScopeMatches,
|
|
103
116
|
actorScope: () => actorScope,
|
|
104
117
|
agentDiagnosticKey: () => agentDiagnosticKey,
|
|
105
118
|
agentFailureCode: () => agentFailureCode,
|
|
106
119
|
askInputSchema: () => askInputSchema,
|
|
107
120
|
askToolDefinition: () => askToolDefinition,
|
|
121
|
+
assertIndependentActionCapabilities: () => assertIndependentActionCapabilities,
|
|
122
|
+
attachActionProposalOutcome: () => attachActionProposalOutcome,
|
|
108
123
|
bucketByActor: () => bucketByActor,
|
|
109
124
|
bucketByModel: () => bucketByModel,
|
|
110
125
|
bucketByThread: () => bucketByThread,
|
|
@@ -112,12 +127,16 @@ __export(src_exports, {
|
|
|
112
127
|
buildMemoryBlock: () => buildMemoryBlock,
|
|
113
128
|
buildSkillsBlock: () => buildSkillsBlock,
|
|
114
129
|
canActorUseTool: () => canActorUseTool,
|
|
115
|
-
|
|
130
|
+
canonicalActionProposalJson: () => canonicalActionProposalJson,
|
|
131
|
+
canonicalJson: () => canonicalJson2,
|
|
132
|
+
claimActionProposalOutcome: () => claimActionProposalOutcome,
|
|
116
133
|
closeEmptyRoles: () => closeEmptyRoles,
|
|
117
134
|
compositeSkillProvider: () => compositeSkillProvider,
|
|
118
135
|
confirmTokenExpiry: () => confirmTokenExpiry,
|
|
119
136
|
createFrameBuffer: () => createFrameBuffer,
|
|
137
|
+
createFunctionalTool: () => createFunctionalTool,
|
|
120
138
|
createIncrementalGate: () => createIncrementalGate,
|
|
139
|
+
createNegotiatedUiCollector: () => createNegotiatedUiCollector,
|
|
121
140
|
createNoopEmitUi: () => createNoopEmitUi,
|
|
122
141
|
createUiCollector: () => createUiCollector,
|
|
123
142
|
danglingToolCallIds: () => danglingToolCallIds,
|
|
@@ -129,7 +148,9 @@ __export(src_exports, {
|
|
|
129
148
|
detachedDelivered: () => detachedDelivered,
|
|
130
149
|
detachedStarted: () => detachedStarted,
|
|
131
150
|
detachedUnsettled: () => detachedUnsettled,
|
|
151
|
+
emitToolPresentations: () => emitToolPresentations,
|
|
132
152
|
encodeStreamEvent: () => encodeStreamEvent,
|
|
153
|
+
escapeUnsafeToolUiText: () => escapeUnsafeToolUiText,
|
|
133
154
|
estimateCost: () => estimateCost,
|
|
134
155
|
estimateMessageTokens: () => estimateMessageTokens,
|
|
135
156
|
exhaustedWindow: () => exhaustedWindow,
|
|
@@ -144,6 +165,7 @@ __export(src_exports, {
|
|
|
144
165
|
gateFollowUps: () => gateFollowUps,
|
|
145
166
|
gateTail: () => gateTail,
|
|
146
167
|
hashConfirmToken: () => hashConfirmToken,
|
|
168
|
+
initialActionProposal: () => initialActionProposal,
|
|
147
169
|
intersectAllowLists: () => intersectAllowLists,
|
|
148
170
|
invokeWithTransientRetry: () => invokeWithTransientRetry,
|
|
149
171
|
isChatQueueStore: () => isChatQueueStore,
|
|
@@ -162,7 +184,10 @@ __export(src_exports, {
|
|
|
162
184
|
observeTurnFrames: () => observeTurnFrames,
|
|
163
185
|
offerMemories: () => offerMemories,
|
|
164
186
|
offerSkills: () => offerSkills,
|
|
187
|
+
parseTextActionProposalCommand: () => parseTextActionProposalCommand,
|
|
165
188
|
personaCatalogEntry: () => personaCatalogEntry,
|
|
189
|
+
prepareActionProposal: () => prepareActionProposal,
|
|
190
|
+
ptBrActionProposalText: () => ptBrActionProposalText,
|
|
166
191
|
publishAgentDelegated: () => publishAgentDelegated,
|
|
167
192
|
publishAgentMemoryResolved: () => publishAgentMemoryResolved,
|
|
168
193
|
publishAgentMemoryWritten: () => publishAgentMemoryWritten,
|
|
@@ -188,12 +213,14 @@ __export(src_exports, {
|
|
|
188
213
|
rememberToolDefinition: () => rememberToolDefinition,
|
|
189
214
|
renderElicitationAnswers: () => renderElicitationAnswers,
|
|
190
215
|
repairInstruction: () => repairInstruction,
|
|
216
|
+
resolveActionProposalApproval: () => resolveActionProposalApproval,
|
|
191
217
|
resolveElicitation: () => resolveElicitation,
|
|
192
218
|
resolveGateLookback: () => resolveGateLookback,
|
|
193
219
|
resolveMemoryDigest: () => resolveMemoryDigest,
|
|
194
220
|
resolveOutputGateMode: () => resolveOutputGateMode,
|
|
195
221
|
resolvePersonaAlias: () => resolvePersonaAlias,
|
|
196
222
|
resolveSkillCatalog: () => resolveSkillCatalog,
|
|
223
|
+
resolveTextActionProposalDecision: () => resolveTextActionProposalDecision,
|
|
197
224
|
resolveToolTransientRetryNumbers: () => resolveToolTransientRetryNumbers,
|
|
198
225
|
rollupThreadUsage: () => rollupThreadUsage,
|
|
199
226
|
runAgentLoop: () => runAgentLoop,
|
|
@@ -210,18 +237,32 @@ __export(src_exports, {
|
|
|
210
237
|
skillInputSchema: () => skillInputSchema,
|
|
211
238
|
skillToolDefinition: () => skillToolDefinition,
|
|
212
239
|
skillWriteVerdict: () => skillWriteVerdict,
|
|
240
|
+
snapshotActionProposal: () => snapshotActionProposal,
|
|
213
241
|
stampToolKinds: () => stampToolKinds,
|
|
214
242
|
staticModelCatalog: () => staticModelCatalog,
|
|
215
243
|
staticSkillProvider: () => staticSkillProvider,
|
|
216
244
|
streamFailure: () => streamFailure,
|
|
217
245
|
summarizeWithModel: () => summarizeWithModel,
|
|
218
246
|
tenantScope: () => tenantScope,
|
|
247
|
+
textActionProposalReply: () => textActionProposalReply,
|
|
248
|
+
toActionProposalMutationView: () => toActionProposalMutationView,
|
|
249
|
+
toActionProposalView: () => toActionProposalView,
|
|
219
250
|
toolCallApprovalFromRow: () => toolCallApprovalFromRow,
|
|
220
251
|
toolCallContext: () => toolCallContext,
|
|
221
252
|
traceLlmTurn: () => traceLlmTurn,
|
|
222
253
|
traceToolExecution: () => traceToolExecution,
|
|
254
|
+
transitionActionProposalClaim: () => transitionActionProposalClaim,
|
|
255
|
+
transitionActionProposalDecision: () => transitionActionProposalDecision,
|
|
256
|
+
transitionActionProposalLease: () => transitionActionProposalLease,
|
|
257
|
+
transitionActionProposalSettlement: () => transitionActionProposalSettlement,
|
|
258
|
+
transitionActionProposalSupersession: () => transitionActionProposalSupersession,
|
|
223
259
|
truncateDetailContent: () => truncateDetailContent,
|
|
224
260
|
unwrapToolStepOutput: () => unwrapToolStepOutput,
|
|
261
|
+
validateActionProposalCreation: () => validateActionProposalCreation,
|
|
262
|
+
validateActionProposalDiscoveryIndexBatch: () => validateActionProposalDiscoveryIndexBatch,
|
|
263
|
+
validateActionProposalExpiryBatch: () => validateActionProposalExpiryBatch,
|
|
264
|
+
validateActionProposalListQuery: () => validateActionProposalListQuery,
|
|
265
|
+
validateActionProposalWorkerClaim: () => validateActionProposalWorkerClaim,
|
|
225
266
|
validateElicitationAnswer: () => validateElicitationAnswer,
|
|
226
267
|
validateElicitationValue: () => validateElicitationValue,
|
|
227
268
|
validateStructured: () => validateStructured,
|
|
@@ -234,6 +275,7 @@ __export(src_exports, {
|
|
|
234
275
|
withSkillTool: () => withSkillTool,
|
|
235
276
|
withToolTimeout: () => withToolTimeout,
|
|
236
277
|
withTurnFrames: () => withTurnFrames,
|
|
278
|
+
wrapToolPreflightDenied: () => wrapToolPreflightDenied,
|
|
237
279
|
wrapToolStepOutput: () => wrapToolStepOutput,
|
|
238
280
|
writeMemory: () => writeMemory
|
|
239
281
|
});
|
|
@@ -407,16 +449,16 @@ function observeTurnFrames(writer, now = Date.now) {
|
|
|
407
449
|
};
|
|
408
450
|
}
|
|
409
451
|
__name(observeTurnFrames, "observeTurnFrames");
|
|
410
|
-
function withTurnFrames(
|
|
452
|
+
function withTurnFrames(result2, frames) {
|
|
411
453
|
return {
|
|
412
|
-
...
|
|
413
|
-
...
|
|
454
|
+
...result2,
|
|
455
|
+
...result2.reasoning === void 0 && frames.reasoning !== void 0 ? {
|
|
414
456
|
reasoning: frames.reasoning
|
|
415
457
|
} : {},
|
|
416
|
-
...
|
|
458
|
+
...result2.reasoningMs === void 0 && frames.reasoningMs !== void 0 ? {
|
|
417
459
|
reasoningMs: frames.reasoningMs
|
|
418
460
|
} : {},
|
|
419
|
-
...
|
|
461
|
+
...result2.ui === void 0 && frames.ui !== void 0 ? {
|
|
420
462
|
ui: frames.ui
|
|
421
463
|
} : {}
|
|
422
464
|
};
|
|
@@ -425,8 +467,9 @@ __name(withTurnFrames, "withTurnFrames");
|
|
|
425
467
|
|
|
426
468
|
// src/tool-ui.ts
|
|
427
469
|
var TOOL_STEP_UI = "@@nestjs-agent/tool-step-ui";
|
|
428
|
-
function wrapToolStepOutput(output, ui) {
|
|
429
|
-
|
|
470
|
+
function wrapToolStepOutput(output, ui, text) {
|
|
471
|
+
const reserved = typeof output === "object" && output !== null && TOOL_STEP_UI in output;
|
|
472
|
+
if (ui.length === 0 && !reserved && !text) {
|
|
430
473
|
return output;
|
|
431
474
|
}
|
|
432
475
|
const wrapped = {
|
|
@@ -434,17 +477,36 @@ function wrapToolStepOutput(output, ui) {
|
|
|
434
477
|
output,
|
|
435
478
|
ui: [
|
|
436
479
|
...ui
|
|
437
|
-
]
|
|
480
|
+
],
|
|
481
|
+
...text ? {
|
|
482
|
+
text
|
|
483
|
+
} : {}
|
|
438
484
|
};
|
|
439
485
|
return wrapped;
|
|
440
486
|
}
|
|
441
487
|
__name(wrapToolStepOutput, "wrapToolStepOutput");
|
|
488
|
+
function wrapToolPreflightDenied(reason) {
|
|
489
|
+
const wrapped = {
|
|
490
|
+
[TOOL_STEP_UI]: 1,
|
|
491
|
+
output: null,
|
|
492
|
+
ui: [],
|
|
493
|
+
preflightDenied: reason
|
|
494
|
+
};
|
|
495
|
+
return wrapped;
|
|
496
|
+
}
|
|
497
|
+
__name(wrapToolPreflightDenied, "wrapToolPreflightDenied");
|
|
442
498
|
function unwrapToolStepOutput(raw) {
|
|
443
499
|
if (typeof raw === "object" && raw !== null && raw[TOOL_STEP_UI] === 1) {
|
|
444
500
|
const wrapped = raw;
|
|
445
501
|
return {
|
|
446
502
|
output: wrapped.output,
|
|
447
|
-
ui: Array.isArray(wrapped.ui) ? wrapped.ui : []
|
|
503
|
+
ui: Array.isArray(wrapped.ui) ? wrapped.ui : [],
|
|
504
|
+
...typeof wrapped.text === "string" ? {
|
|
505
|
+
text: wrapped.text
|
|
506
|
+
} : {},
|
|
507
|
+
...typeof wrapped.preflightDenied === "string" ? {
|
|
508
|
+
preflightDenied: wrapped.preflightDenied
|
|
509
|
+
} : {}
|
|
448
510
|
};
|
|
449
511
|
}
|
|
450
512
|
return {
|
|
@@ -493,6 +555,14 @@ function createUiCollector(toolCallId, write) {
|
|
|
493
555
|
...options.version !== void 0 ? {
|
|
494
556
|
version: options.version
|
|
495
557
|
} : {},
|
|
558
|
+
...options.fallbackText !== void 0 ? {
|
|
559
|
+
fallbackText: options.fallbackText
|
|
560
|
+
} : {},
|
|
561
|
+
...options.componentVersions !== void 0 ? {
|
|
562
|
+
componentVersions: {
|
|
563
|
+
...options.componentVersions
|
|
564
|
+
}
|
|
565
|
+
} : {},
|
|
496
566
|
toolCallId
|
|
497
567
|
};
|
|
498
568
|
pushed.set(id, entry);
|
|
@@ -527,6 +597,10 @@ function mergeUi(...lists) {
|
|
|
527
597
|
];
|
|
528
598
|
}
|
|
529
599
|
__name(mergeUi, "mergeUi");
|
|
600
|
+
function escapeUnsafeToolUiText(text) {
|
|
601
|
+
return text.replaceAll("\0", "\\u0000").replace(/[\uD800-\uDFFF]/gu, (unit) => `\\u${unit.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
602
|
+
}
|
|
603
|
+
__name(escapeUnsafeToolUiText, "escapeUnsafeToolUiText");
|
|
530
604
|
|
|
531
605
|
// src/tool-presentation.ts
|
|
532
606
|
var ALL_AGENTS = "*";
|
|
@@ -734,31 +808,37 @@ async function mayDecideApproval(policy, actor, decision) {
|
|
|
734
808
|
return defaultCanDecide(actor, decision);
|
|
735
809
|
}
|
|
736
810
|
__name(mayDecideApproval, "mayDecideApproval");
|
|
737
|
-
function toolCallApprovalFromRow(
|
|
738
|
-
if (
|
|
811
|
+
function toolCallApprovalFromRow(row2) {
|
|
812
|
+
if (row2.approver === null || row2.approver === void 0) {
|
|
739
813
|
return null;
|
|
740
814
|
}
|
|
741
|
-
const status =
|
|
742
|
-
const expiresAt =
|
|
815
|
+
const status = row2.status === "pending_approval" || row2.status === "proposed" ? "pending" : row2.status === "rejected" ? "rejected" : row2.status === "expired" ? "expired" : "approved";
|
|
816
|
+
const expiresAt = row2.expiresAt instanceof Date ? row2.expiresAt.toISOString() : typeof row2.expiresAt === "string" ? row2.expiresAt : void 0;
|
|
743
817
|
const decided = status === "approved" || status === "rejected";
|
|
744
818
|
return {
|
|
745
|
-
toolCallId:
|
|
746
|
-
|
|
819
|
+
toolCallId: row2.toolCallId,
|
|
820
|
+
...row2.proposalId != null ? {
|
|
821
|
+
proposalId: row2.proposalId
|
|
822
|
+
} : {},
|
|
823
|
+
approver: row2.approver,
|
|
824
|
+
...row2.confirmation != null ? {
|
|
825
|
+
confirmation: row2.confirmation
|
|
826
|
+
} : {},
|
|
747
827
|
status,
|
|
748
828
|
...expiresAt !== void 0 ? {
|
|
749
829
|
expiresAt
|
|
750
830
|
} : {},
|
|
751
|
-
...
|
|
831
|
+
...row2.remember === true ? {
|
|
752
832
|
remember: true
|
|
753
833
|
} : {},
|
|
754
|
-
...decided && typeof
|
|
755
|
-
decidedBy:
|
|
834
|
+
...decided && typeof row2.executedByRef === "string" ? {
|
|
835
|
+
decidedBy: row2.executedByRef
|
|
756
836
|
} : {},
|
|
757
|
-
...decided && typeof
|
|
758
|
-
decidedVia:
|
|
837
|
+
...decided && typeof row2.decidedVia === "string" ? {
|
|
838
|
+
decidedVia: row2.decidedVia
|
|
759
839
|
} : {},
|
|
760
|
-
...status === "rejected" && typeof
|
|
761
|
-
reason:
|
|
840
|
+
...status === "rejected" && typeof row2.error === "string" ? {
|
|
841
|
+
reason: row2.error
|
|
762
842
|
} : {}
|
|
763
843
|
};
|
|
764
844
|
}
|
|
@@ -775,28 +855,28 @@ function estimateCost(usage, price) {
|
|
|
775
855
|
return uncachedInputTokens / 1e6 * price.inputPricePer1m + cacheWriteTokens / 1e6 * (price.cacheWritePricePer1m ?? price.inputPricePer1m) + cacheReadTokens / 1e6 * (price.cacheReadPricePer1m ?? price.inputPricePer1m) + usage.outputTokens / 1e6 * price.outputPricePer1m;
|
|
776
856
|
}
|
|
777
857
|
__name(estimateCost, "estimateCost");
|
|
778
|
-
function rowCost(
|
|
779
|
-
return
|
|
858
|
+
function rowCost(row2, prices) {
|
|
859
|
+
return row2.costUsd ?? estimateCost(row2, prices.get(row2.modelId));
|
|
780
860
|
}
|
|
781
861
|
__name(rowCost, "rowCost");
|
|
782
862
|
function bucketByModel(rows, prices) {
|
|
783
863
|
const byModel = /* @__PURE__ */ new Map();
|
|
784
|
-
for (const
|
|
785
|
-
const bucket = byModel.get(
|
|
864
|
+
for (const row2 of rows) {
|
|
865
|
+
const bucket = byModel.get(row2.modelId) ?? {
|
|
786
866
|
requests: 0,
|
|
787
867
|
inputTokens: 0,
|
|
788
868
|
outputTokens: 0,
|
|
789
869
|
costUsd: 0
|
|
790
870
|
};
|
|
791
871
|
bucket.requests += 1;
|
|
792
|
-
bucket.inputTokens +=
|
|
793
|
-
bucket.outputTokens +=
|
|
794
|
-
bucket.costUsd += rowCost(
|
|
795
|
-
byModel.set(
|
|
872
|
+
bucket.inputTokens += row2.inputTokens;
|
|
873
|
+
bucket.outputTokens += row2.outputTokens;
|
|
874
|
+
bucket.costUsd += rowCost(row2, prices);
|
|
875
|
+
byModel.set(row2.modelId, bucket);
|
|
796
876
|
}
|
|
797
|
-
const
|
|
877
|
+
const result2 = [];
|
|
798
878
|
for (const [modelId, bucket] of byModel) {
|
|
799
|
-
|
|
879
|
+
result2.push({
|
|
800
880
|
modelId,
|
|
801
881
|
requests: bucket.requests,
|
|
802
882
|
inputTokens: bucket.inputTokens,
|
|
@@ -804,28 +884,28 @@ function bucketByModel(rows, prices) {
|
|
|
804
884
|
costUsd: bucket.costUsd
|
|
805
885
|
});
|
|
806
886
|
}
|
|
807
|
-
|
|
808
|
-
return
|
|
887
|
+
result2.sort((left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId));
|
|
888
|
+
return result2;
|
|
809
889
|
}
|
|
810
890
|
__name(bucketByModel, "bucketByModel");
|
|
811
891
|
function bucketByActor(rows, prices) {
|
|
812
892
|
const byActor = /* @__PURE__ */ new Map();
|
|
813
|
-
for (const
|
|
814
|
-
const bucket = byActor.get(
|
|
893
|
+
for (const row2 of rows) {
|
|
894
|
+
const bucket = byActor.get(row2.actorRef) ?? {
|
|
815
895
|
requests: 0,
|
|
816
896
|
totalTokens: 0,
|
|
817
897
|
costUsd: 0,
|
|
818
898
|
threadIds: /* @__PURE__ */ new Set()
|
|
819
899
|
};
|
|
820
900
|
bucket.requests += 1;
|
|
821
|
-
bucket.totalTokens +=
|
|
822
|
-
bucket.costUsd += rowCost(
|
|
823
|
-
bucket.threadIds.add(
|
|
824
|
-
byActor.set(
|
|
901
|
+
bucket.totalTokens += row2.inputTokens + row2.outputTokens;
|
|
902
|
+
bucket.costUsd += rowCost(row2, prices);
|
|
903
|
+
bucket.threadIds.add(row2.threadId);
|
|
904
|
+
byActor.set(row2.actorRef, bucket);
|
|
825
905
|
}
|
|
826
|
-
const
|
|
906
|
+
const result2 = [];
|
|
827
907
|
for (const [actorRef, bucket] of byActor) {
|
|
828
|
-
|
|
908
|
+
result2.push({
|
|
829
909
|
actorRef,
|
|
830
910
|
requests: bucket.requests,
|
|
831
911
|
totalTokens: bucket.totalTokens,
|
|
@@ -833,30 +913,30 @@ function bucketByActor(rows, prices) {
|
|
|
833
913
|
threadCount: bucket.threadIds.size
|
|
834
914
|
});
|
|
835
915
|
}
|
|
836
|
-
|
|
837
|
-
return
|
|
916
|
+
result2.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
|
|
917
|
+
return result2;
|
|
838
918
|
}
|
|
839
919
|
__name(bucketByActor, "bucketByActor");
|
|
840
920
|
function bucketByThread(rows, prices, threads, options) {
|
|
841
921
|
const byThread = /* @__PURE__ */ new Map();
|
|
842
|
-
for (const
|
|
843
|
-
const bucket = byThread.get(
|
|
922
|
+
for (const row2 of rows) {
|
|
923
|
+
const bucket = byThread.get(row2.threadId) ?? {
|
|
844
924
|
requests: 0,
|
|
845
925
|
totalTokens: 0,
|
|
846
926
|
costUsd: 0
|
|
847
927
|
};
|
|
848
928
|
bucket.requests += 1;
|
|
849
|
-
bucket.totalTokens +=
|
|
850
|
-
bucket.costUsd += rowCost(
|
|
851
|
-
byThread.set(
|
|
929
|
+
bucket.totalTokens += row2.inputTokens + row2.outputTokens;
|
|
930
|
+
bucket.costUsd += rowCost(row2, prices);
|
|
931
|
+
byThread.set(row2.threadId, bucket);
|
|
852
932
|
}
|
|
853
|
-
const
|
|
933
|
+
const result2 = [];
|
|
854
934
|
for (const [threadId, bucket] of byThread) {
|
|
855
935
|
const thread = threads.get(threadId);
|
|
856
936
|
if (thread === void 0 && !options.includeUnknownThreads) {
|
|
857
937
|
continue;
|
|
858
938
|
}
|
|
859
|
-
|
|
939
|
+
result2.push({
|
|
860
940
|
threadId,
|
|
861
941
|
title: thread?.title ?? "",
|
|
862
942
|
actorRef: thread?.actorRef ?? "",
|
|
@@ -865,8 +945,8 @@ function bucketByThread(rows, prices, threads, options) {
|
|
|
865
945
|
costUsd: bucket.costUsd
|
|
866
946
|
});
|
|
867
947
|
}
|
|
868
|
-
|
|
869
|
-
return
|
|
948
|
+
result2.sort((left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId));
|
|
949
|
+
return result2.slice(0, options.limit);
|
|
870
950
|
}
|
|
871
951
|
__name(bucketByThread, "bucketByThread");
|
|
872
952
|
function rollupThreadUsage(rows, prices) {
|
|
@@ -877,37 +957,37 @@ function rollupThreadUsage(rows, prices) {
|
|
|
877
957
|
totalTokens: 0,
|
|
878
958
|
costUsd: 0
|
|
879
959
|
};
|
|
880
|
-
for (const
|
|
960
|
+
for (const row2 of rows) {
|
|
881
961
|
rollup.requests += 1;
|
|
882
|
-
rollup.inputTokens +=
|
|
883
|
-
rollup.outputTokens +=
|
|
884
|
-
rollup.totalTokens +=
|
|
885
|
-
rollup.costUsd += rowCost(
|
|
962
|
+
rollup.inputTokens += row2.inputTokens;
|
|
963
|
+
rollup.outputTokens += row2.outputTokens;
|
|
964
|
+
rollup.totalTokens += row2.inputTokens + row2.outputTokens;
|
|
965
|
+
rollup.costUsd += rowCost(row2, prices);
|
|
886
966
|
}
|
|
887
967
|
return rollup;
|
|
888
968
|
}
|
|
889
969
|
__name(rollupThreadUsage, "rollupThreadUsage");
|
|
890
970
|
function bucketUsageTrend(rows, prices) {
|
|
891
971
|
const byDay = /* @__PURE__ */ new Map();
|
|
892
|
-
for (const
|
|
893
|
-
const bucket = byDay.get(
|
|
972
|
+
for (const row2 of rows) {
|
|
973
|
+
const bucket = byDay.get(row2.day) ?? {
|
|
894
974
|
totalTokens: 0,
|
|
895
975
|
costUsd: 0
|
|
896
976
|
};
|
|
897
|
-
bucket.totalTokens +=
|
|
898
|
-
bucket.costUsd += rowCost(
|
|
899
|
-
byDay.set(
|
|
977
|
+
bucket.totalTokens += row2.inputTokens + row2.outputTokens;
|
|
978
|
+
bucket.costUsd += rowCost(row2, prices);
|
|
979
|
+
byDay.set(row2.day, bucket);
|
|
900
980
|
}
|
|
901
|
-
const
|
|
981
|
+
const result2 = [];
|
|
902
982
|
for (const [day, bucket] of byDay) {
|
|
903
|
-
|
|
983
|
+
result2.push({
|
|
904
984
|
day,
|
|
905
985
|
totalTokens: bucket.totalTokens,
|
|
906
986
|
costUsd: bucket.costUsd
|
|
907
987
|
});
|
|
908
988
|
}
|
|
909
|
-
|
|
910
|
-
return
|
|
989
|
+
result2.sort((left, right) => left.day.localeCompare(right.day));
|
|
990
|
+
return result2;
|
|
911
991
|
}
|
|
912
992
|
__name(bucketUsageTrend, "bucketUsageTrend");
|
|
913
993
|
function dayBoundsUtc(range) {
|
|
@@ -932,7 +1012,7 @@ async function filterToolsByEnabled(entries) {
|
|
|
932
1012
|
entry,
|
|
933
1013
|
enabled: await isToolEnabled(entry.spec, entry.handler)
|
|
934
1014
|
})));
|
|
935
|
-
return checked.filter((
|
|
1015
|
+
return checked.filter((row2) => row2.enabled).map((row2) => row2.entry);
|
|
936
1016
|
}
|
|
937
1017
|
__name(filterToolsByEnabled, "filterToolsByEnabled");
|
|
938
1018
|
async function canActorUseTool(actor, handler) {
|
|
@@ -944,7 +1024,7 @@ async function filterToolsByCanUse(entries, actor) {
|
|
|
944
1024
|
entry,
|
|
945
1025
|
allowed: await canActorUseTool(actor, entry.handler)
|
|
946
1026
|
})));
|
|
947
|
-
return checked.filter((
|
|
1027
|
+
return checked.filter((row2) => row2.allowed).map((row2) => row2.entry);
|
|
948
1028
|
}
|
|
949
1029
|
__name(filterToolsByCanUse, "filterToolsByCanUse");
|
|
950
1030
|
async function filterToolsByRole(tools, actor, policy) {
|
|
@@ -1351,13 +1431,13 @@ async function validateStructured(schema, text, reported) {
|
|
|
1351
1431
|
issues: []
|
|
1352
1432
|
};
|
|
1353
1433
|
}
|
|
1354
|
-
const
|
|
1355
|
-
return
|
|
1434
|
+
const result2 = await schema["~standard"].validate(candidate);
|
|
1435
|
+
return result2.issues !== void 0 ? {
|
|
1356
1436
|
ok: false,
|
|
1357
|
-
issues:
|
|
1437
|
+
issues: result2.issues
|
|
1358
1438
|
} : {
|
|
1359
1439
|
ok: true,
|
|
1360
|
-
value:
|
|
1440
|
+
value: result2.value
|
|
1361
1441
|
};
|
|
1362
1442
|
}
|
|
1363
1443
|
__name(validateStructured, "validateStructured");
|
|
@@ -2536,12 +2616,12 @@ function memoryWriteVerdict(request) {
|
|
|
2536
2616
|
};
|
|
2537
2617
|
}
|
|
2538
2618
|
__name(memoryWriteVerdict, "memoryWriteVerdict");
|
|
2539
|
-
function memoryForgetVerdict({ record, actor }) {
|
|
2540
|
-
return
|
|
2619
|
+
function memoryForgetVerdict({ record: record2, actor }) {
|
|
2620
|
+
return record2.scope === actorScope(actor) ? {
|
|
2541
2621
|
allowed: true
|
|
2542
2622
|
} : {
|
|
2543
2623
|
allowed: false,
|
|
2544
|
-
reason: `"${
|
|
2624
|
+
reason: `"${record2.scope}" is not this actor's own scope; deleting it is an administrative action`
|
|
2545
2625
|
};
|
|
2546
2626
|
}
|
|
2547
2627
|
__name(memoryForgetVerdict, "memoryForgetVerdict");
|
|
@@ -2584,7 +2664,7 @@ async function writeMemory({ config, digest, call, ctx, runId }) {
|
|
|
2584
2664
|
error: verdict.reason
|
|
2585
2665
|
};
|
|
2586
2666
|
}
|
|
2587
|
-
const
|
|
2667
|
+
const record2 = await write({
|
|
2588
2668
|
key,
|
|
2589
2669
|
text,
|
|
2590
2670
|
scope,
|
|
@@ -2598,7 +2678,7 @@ async function writeMemory({ config, digest, call, ctx, runId }) {
|
|
|
2598
2678
|
});
|
|
2599
2679
|
return {
|
|
2600
2680
|
ok: true,
|
|
2601
|
-
record
|
|
2681
|
+
record: record2
|
|
2602
2682
|
};
|
|
2603
2683
|
}
|
|
2604
2684
|
__name(writeMemory, "writeMemory");
|
|
@@ -2650,7 +2730,7 @@ function danglingToolCallIds(messages) {
|
|
|
2650
2730
|
if (message.role !== "assistant" || calls.length === 0) {
|
|
2651
2731
|
continue;
|
|
2652
2732
|
}
|
|
2653
|
-
const settled = new Set((message.toolResults ?? []).map((
|
|
2733
|
+
const settled = new Set((message.toolResults ?? []).map((result2) => result2.id));
|
|
2654
2734
|
for (const call of calls) {
|
|
2655
2735
|
if (!settled.has(call.id)) {
|
|
2656
2736
|
ids.push(call.id);
|
|
@@ -2718,7 +2798,7 @@ function settleDanglingToolCalls(messages, outcomes = []) {
|
|
|
2718
2798
|
return message;
|
|
2719
2799
|
}
|
|
2720
2800
|
const results = message.toolResults ?? [];
|
|
2721
|
-
const settled = new Set(results.map((
|
|
2801
|
+
const settled = new Set(results.map((result2) => result2.id));
|
|
2722
2802
|
const missing = calls.filter((call) => !settled.has(call.id));
|
|
2723
2803
|
if (missing.length === 0) {
|
|
2724
2804
|
return message;
|
|
@@ -2826,6 +2906,1665 @@ async function settleUnsettledDelegation(args) {
|
|
|
2826
2906
|
}
|
|
2827
2907
|
__name(settleUnsettledDelegation, "settleUnsettledDelegation");
|
|
2828
2908
|
|
|
2909
|
+
// src/action-proposal-discovery.ts
|
|
2910
|
+
function validateActionProposalWorkerClaim(command, now) {
|
|
2911
|
+
if (!Number.isSafeInteger(now)) throw new RangeError("Invalid action proposal clock");
|
|
2912
|
+
if (typeof command.workerId !== "string" || command.workerId.length === 0) throw new TypeError("workerId must be a nonempty string");
|
|
2913
|
+
if (!Number.isSafeInteger(command.leaseMs) || command.leaseMs <= 0 || !Number.isSafeInteger(now + command.leaseMs)) throw new RangeError("leaseMs must be positive safe integer milliseconds");
|
|
2914
|
+
}
|
|
2915
|
+
__name(validateActionProposalWorkerClaim, "validateActionProposalWorkerClaim");
|
|
2916
|
+
function validateActionProposalExpiryBatch(command, now) {
|
|
2917
|
+
if (!Number.isSafeInteger(now)) throw new RangeError("Invalid action proposal clock");
|
|
2918
|
+
validateActionProposalDiscoveryIndexBatch(command);
|
|
2919
|
+
}
|
|
2920
|
+
__name(validateActionProposalExpiryBatch, "validateActionProposalExpiryBatch");
|
|
2921
|
+
function validateActionProposalDiscoveryIndexBatch(command) {
|
|
2922
|
+
if (!Number.isInteger(command.limit) || command.limit < 1 || command.limit > 1e3) throw new RangeError("limit must be an integer from 1 to 1000");
|
|
2923
|
+
}
|
|
2924
|
+
__name(validateActionProposalDiscoveryIndexBatch, "validateActionProposalDiscoveryIndexBatch");
|
|
2925
|
+
|
|
2926
|
+
// src/action-proposal-outcome.ts
|
|
2927
|
+
function attachActionProposalOutcome(row2, now, ui = [], text) {
|
|
2928
|
+
if (row2.outcome) return row2;
|
|
2929
|
+
const execution = row2.execution;
|
|
2930
|
+
const outcome = {
|
|
2931
|
+
id: `${row2.id}:outcome:1`,
|
|
2932
|
+
proposalId: row2.id,
|
|
2933
|
+
outcomeVersion: 1,
|
|
2934
|
+
tenantRef: row2.tenantRef,
|
|
2935
|
+
actorRef: row2.actorRef,
|
|
2936
|
+
threadId: row2.threadId,
|
|
2937
|
+
originRunId: row2.originRunId,
|
|
2938
|
+
originToolCallId: row2.originToolCallId,
|
|
2939
|
+
toolName: row2.toolName,
|
|
2940
|
+
decision: row2.decision,
|
|
2941
|
+
ui,
|
|
2942
|
+
createdAt: now,
|
|
2943
|
+
...text !== void 0 ? {
|
|
2944
|
+
text
|
|
2945
|
+
} : {},
|
|
2946
|
+
...execution?.status === "succeeded" || execution?.status === "failed" ? {
|
|
2947
|
+
executionStatus: execution.status
|
|
2948
|
+
} : {},
|
|
2949
|
+
...execution && Object.hasOwn(execution, "result") ? {
|
|
2950
|
+
result: execution.result
|
|
2951
|
+
} : {},
|
|
2952
|
+
...execution?.error !== void 0 ? {
|
|
2953
|
+
error: execution.error
|
|
2954
|
+
} : row2.decisionAudit?.reason !== void 0 ? {
|
|
2955
|
+
error: row2.decisionAudit.reason
|
|
2956
|
+
} : {}
|
|
2957
|
+
};
|
|
2958
|
+
return snapshotActionProposal({
|
|
2959
|
+
...row2,
|
|
2960
|
+
outcome,
|
|
2961
|
+
outcomeDelivery: {
|
|
2962
|
+
status: "pending",
|
|
2963
|
+
generation: 0,
|
|
2964
|
+
lease: null
|
|
2965
|
+
}
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2968
|
+
__name(attachActionProposalOutcome, "attachActionProposalOutcome");
|
|
2969
|
+
function claimActionProposalOutcome(row2, command, now, token) {
|
|
2970
|
+
validateActionProposalWorkerClaim(command, now);
|
|
2971
|
+
const delivery = row2.outcomeDelivery;
|
|
2972
|
+
if (!row2.outcome || !delivery || delivery.status !== "pending" || delivery.lease && now < delivery.lease.expiresAt) return null;
|
|
2973
|
+
const generation = delivery.generation + 1;
|
|
2974
|
+
return snapshotActionProposal({
|
|
2975
|
+
...row2,
|
|
2976
|
+
outcomeDelivery: {
|
|
2977
|
+
...delivery,
|
|
2978
|
+
generation,
|
|
2979
|
+
lease: {
|
|
2980
|
+
token,
|
|
2981
|
+
generation,
|
|
2982
|
+
workerId: command.workerId,
|
|
2983
|
+
expiresAt: now + command.leaseMs
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
2988
|
+
__name(claimActionProposalOutcome, "claimActionProposalOutcome");
|
|
2989
|
+
function actionProposalOutcomeFenceValid(row2, command, now) {
|
|
2990
|
+
if (!Number.isSafeInteger(now)) throw new RangeError("Invalid server clock");
|
|
2991
|
+
if (typeof command.token !== "string" || !command.token || !Number.isSafeInteger(command.generation) || command.generation < 1 || typeof command.outcomeId !== "string" || !command.outcomeId) throw new TypeError("Invalid outcome fence");
|
|
2992
|
+
const delivery = row2.outcomeDelivery;
|
|
2993
|
+
return row2.outcome?.id === command.outcomeId && delivery?.status === "pending" && delivery.generation === command.generation && delivery.lease?.token === command.token && delivery.lease.generation === command.generation && now < delivery.lease.expiresAt;
|
|
2994
|
+
}
|
|
2995
|
+
__name(actionProposalOutcomeFenceValid, "actionProposalOutcomeFenceValid");
|
|
2996
|
+
function outcomeSummary(outcome) {
|
|
2997
|
+
if (outcome.executionStatus === "succeeded") return `Action ${JSON.stringify(outcome.toolName)} completed (proposal ${JSON.stringify(outcome.proposalId)}).${Object.hasOwn(outcome, "result") ? ` Result: ${JSON.stringify(outcome.result)}` : ""}`;
|
|
2998
|
+
if (outcome.executionStatus === "failed") return `Action ${JSON.stringify(outcome.toolName)} failed (proposal ${JSON.stringify(outcome.proposalId)}): ${JSON.stringify(outcome.error ?? "Execution failed")}`;
|
|
2999
|
+
return `Action ${JSON.stringify(outcome.toolName)} was ${outcome.decision} (proposal ${JSON.stringify(outcome.proposalId)}) and was not executed.${outcome.error ? ` Reason: ${JSON.stringify(outcome.error)}` : ""}`;
|
|
3000
|
+
}
|
|
3001
|
+
__name(outcomeSummary, "outcomeSummary");
|
|
3002
|
+
function actionProposalOutcomeScope(outcome) {
|
|
3003
|
+
return {
|
|
3004
|
+
tenantRef: outcome.tenantRef,
|
|
3005
|
+
actorRef: outcome.actorRef,
|
|
3006
|
+
threadId: outcome.threadId
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
__name(actionProposalOutcomeScope, "actionProposalOutcomeScope");
|
|
3010
|
+
function actionProposalOutcomeText(outcome) {
|
|
3011
|
+
return outcomeSummary(outcome) + (outcome.text ? ` UI: ${JSON.stringify(outcome.text)}` : "");
|
|
3012
|
+
}
|
|
3013
|
+
__name(actionProposalOutcomeText, "actionProposalOutcomeText");
|
|
3014
|
+
|
|
3015
|
+
// src/genui/schema.ts
|
|
3016
|
+
function isStandardSchema(schema) {
|
|
3017
|
+
return typeof schema === "object" && schema !== null && "~standard" in schema && typeof schema["~standard"]?.validate === "function";
|
|
3018
|
+
}
|
|
3019
|
+
__name(isStandardSchema, "isStandardSchema");
|
|
3020
|
+
function toJsonSchema(schema) {
|
|
3021
|
+
if (!isStandardSchema(schema)) {
|
|
3022
|
+
return schema;
|
|
3023
|
+
}
|
|
3024
|
+
const standard = schema["~standard"];
|
|
3025
|
+
const converter = standard.jsonSchema;
|
|
3026
|
+
if (converter === void 0 || typeof converter.input !== "function") {
|
|
3027
|
+
return void 0;
|
|
3028
|
+
}
|
|
3029
|
+
try {
|
|
3030
|
+
return converter.input({
|
|
3031
|
+
target: "draft-07"
|
|
3032
|
+
});
|
|
3033
|
+
} catch {
|
|
3034
|
+
return void 0;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
__name(toJsonSchema, "toJsonSchema");
|
|
3038
|
+
async function validateProps(schema, value, validator) {
|
|
3039
|
+
if (isStandardSchema(schema)) {
|
|
3040
|
+
const result2 = await schema["~standard"].validate(value);
|
|
3041
|
+
if (result2.issues !== void 0) {
|
|
3042
|
+
return {
|
|
3043
|
+
ok: false,
|
|
3044
|
+
issues: toGenuiIssues(result2.issues)
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
return {
|
|
3048
|
+
ok: true,
|
|
3049
|
+
value: result2.value
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
const issues = validator.validate(schema, value);
|
|
3053
|
+
return issues.length > 0 ? {
|
|
3054
|
+
ok: false,
|
|
3055
|
+
issues
|
|
3056
|
+
} : {
|
|
3057
|
+
ok: true,
|
|
3058
|
+
value
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
__name(validateProps, "validateProps");
|
|
3062
|
+
function validatePropsSync(schema, value, validator) {
|
|
3063
|
+
if (!isStandardSchema(schema)) {
|
|
3064
|
+
const issues = validator.validate(schema, value);
|
|
3065
|
+
return issues.length > 0 ? {
|
|
3066
|
+
ok: false,
|
|
3067
|
+
issues
|
|
3068
|
+
} : {
|
|
3069
|
+
ok: true,
|
|
3070
|
+
value
|
|
3071
|
+
};
|
|
3072
|
+
}
|
|
3073
|
+
const result2 = schema["~standard"].validate(value);
|
|
3074
|
+
if (result2 instanceof Promise) {
|
|
3075
|
+
result2.catch(() => void 0);
|
|
3076
|
+
return void 0;
|
|
3077
|
+
}
|
|
3078
|
+
return result2.issues !== void 0 ? {
|
|
3079
|
+
ok: false,
|
|
3080
|
+
issues: toGenuiIssues(result2.issues)
|
|
3081
|
+
} : {
|
|
3082
|
+
ok: true,
|
|
3083
|
+
value: result2.value
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
__name(validatePropsSync, "validatePropsSync");
|
|
3087
|
+
function toGenuiIssues(issues) {
|
|
3088
|
+
return issues.map((issue4) => ({
|
|
3089
|
+
path: (issue4.path ?? []).map((segment) => typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment),
|
|
3090
|
+
message: issue4.message
|
|
3091
|
+
}));
|
|
3092
|
+
}
|
|
3093
|
+
__name(toGenuiIssues, "toGenuiIssues");
|
|
3094
|
+
function formatIssues(issues) {
|
|
3095
|
+
return issues.map((issue4) => `${issue4.path.length > 0 ? formatPath(issue4.path) : "(root)"}: ${issue4.message}`).join("; ");
|
|
3096
|
+
}
|
|
3097
|
+
__name(formatIssues, "formatIssues");
|
|
3098
|
+
function formatPath(path) {
|
|
3099
|
+
return path.map((segment, index) => typeof segment === "number" ? `[${segment}]` : index === 0 ? segment : `.${segment}`).join("");
|
|
3100
|
+
}
|
|
3101
|
+
__name(formatPath, "formatPath");
|
|
3102
|
+
var builtinJsonSchemaValidator = {
|
|
3103
|
+
validate(schema, value) {
|
|
3104
|
+
const issues = [];
|
|
3105
|
+
check(schema, value, [], schema, issues, 0);
|
|
3106
|
+
return issues;
|
|
3107
|
+
}
|
|
3108
|
+
};
|
|
3109
|
+
var MAX_DEPTH = 64;
|
|
3110
|
+
function typeOf(value) {
|
|
3111
|
+
if (value === null) return "null";
|
|
3112
|
+
if (Array.isArray(value)) return "array";
|
|
3113
|
+
return typeof value;
|
|
3114
|
+
}
|
|
3115
|
+
__name(typeOf, "typeOf");
|
|
3116
|
+
function matchesType(type, value) {
|
|
3117
|
+
switch (type) {
|
|
3118
|
+
case "integer":
|
|
3119
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
3120
|
+
case "number":
|
|
3121
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
3122
|
+
case "object":
|
|
3123
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3124
|
+
default:
|
|
3125
|
+
return typeOf(value) === type;
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
__name(matchesType, "matchesType");
|
|
3129
|
+
function resolveRef(root, ref) {
|
|
3130
|
+
if (ref === "#") return root;
|
|
3131
|
+
if (!ref.startsWith("#/")) return void 0;
|
|
3132
|
+
let current = root;
|
|
3133
|
+
for (const raw of ref.slice(2).split("/")) {
|
|
3134
|
+
const key = raw.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
3135
|
+
if (typeof current !== "object" || current === null) return void 0;
|
|
3136
|
+
current = current[key];
|
|
3137
|
+
}
|
|
3138
|
+
return typeof current === "object" && current !== null ? current : void 0;
|
|
3139
|
+
}
|
|
3140
|
+
__name(resolveRef, "resolveRef");
|
|
3141
|
+
function deepEqual(a, b) {
|
|
3142
|
+
if (a === b) return true;
|
|
3143
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
3144
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
3145
|
+
const keysA = Object.keys(a);
|
|
3146
|
+
const keysB = Object.keys(b);
|
|
3147
|
+
if (keysA.length !== keysB.length) return false;
|
|
3148
|
+
return keysA.every((key) => deepEqual(a[key], b[key]));
|
|
3149
|
+
}
|
|
3150
|
+
__name(deepEqual, "deepEqual");
|
|
3151
|
+
function check(schema, value, path, root, issues, depth) {
|
|
3152
|
+
if (schema === true || schema === void 0) return;
|
|
3153
|
+
if (schema === false) {
|
|
3154
|
+
issues.push({
|
|
3155
|
+
path,
|
|
3156
|
+
message: "is not allowed"
|
|
3157
|
+
});
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3160
|
+
if (typeof schema !== "object" || schema === null) return;
|
|
3161
|
+
if (depth > MAX_DEPTH) {
|
|
3162
|
+
issues.push({
|
|
3163
|
+
path,
|
|
3164
|
+
message: "is nested too deeply"
|
|
3165
|
+
});
|
|
3166
|
+
return;
|
|
3167
|
+
}
|
|
3168
|
+
const s2 = schema;
|
|
3169
|
+
if (typeof s2.$ref === "string") {
|
|
3170
|
+
const target = resolveRef(root, s2.$ref);
|
|
3171
|
+
if (target === void 0) {
|
|
3172
|
+
issues.push({
|
|
3173
|
+
path,
|
|
3174
|
+
message: `references unknown schema ${s2.$ref}`
|
|
3175
|
+
});
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3178
|
+
check(target, value, path, root, issues, depth + 1);
|
|
3179
|
+
}
|
|
3180
|
+
if (s2.type !== void 0) {
|
|
3181
|
+
const types = Array.isArray(s2.type) ? s2.type : [
|
|
3182
|
+
s2.type
|
|
3183
|
+
];
|
|
3184
|
+
if (!types.some((type) => matchesType(type, value))) {
|
|
3185
|
+
issues.push({
|
|
3186
|
+
path,
|
|
3187
|
+
message: `must be ${types.join(" or ")}`
|
|
3188
|
+
});
|
|
3189
|
+
return;
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
if (Array.isArray(s2.enum) && !s2.enum.some((option) => deepEqual(option, value))) {
|
|
3193
|
+
issues.push({
|
|
3194
|
+
path,
|
|
3195
|
+
message: `must be one of ${s2.enum.map((option) => JSON.stringify(option)).join(", ")}`
|
|
3196
|
+
});
|
|
3197
|
+
}
|
|
3198
|
+
if ("const" in s2 && !deepEqual(s2.const, value)) {
|
|
3199
|
+
issues.push({
|
|
3200
|
+
path,
|
|
3201
|
+
message: `must be ${JSON.stringify(s2.const)}`
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3204
|
+
if (typeof value === "string") {
|
|
3205
|
+
if (typeof s2.minLength === "number" && value.length < s2.minLength) {
|
|
3206
|
+
issues.push({
|
|
3207
|
+
path,
|
|
3208
|
+
message: `must be at least ${s2.minLength} characters`
|
|
3209
|
+
});
|
|
3210
|
+
}
|
|
3211
|
+
if (typeof s2.maxLength === "number" && value.length > s2.maxLength) {
|
|
3212
|
+
issues.push({
|
|
3213
|
+
path,
|
|
3214
|
+
message: `must be at most ${s2.maxLength} characters`
|
|
3215
|
+
});
|
|
3216
|
+
}
|
|
3217
|
+
if (typeof s2.pattern === "string") {
|
|
3218
|
+
let pattern;
|
|
3219
|
+
try {
|
|
3220
|
+
pattern = new RegExp(s2.pattern, "u");
|
|
3221
|
+
} catch {
|
|
3222
|
+
pattern = void 0;
|
|
3223
|
+
}
|
|
3224
|
+
if (pattern !== void 0 && !pattern.test(value)) {
|
|
3225
|
+
issues.push({
|
|
3226
|
+
path,
|
|
3227
|
+
message: `must match ${s2.pattern}`
|
|
3228
|
+
});
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
if (typeof value === "number") {
|
|
3233
|
+
if (typeof s2.minimum === "number" && value < s2.minimum) {
|
|
3234
|
+
issues.push({
|
|
3235
|
+
path,
|
|
3236
|
+
message: `must be >= ${s2.minimum}`
|
|
3237
|
+
});
|
|
3238
|
+
}
|
|
3239
|
+
if (typeof s2.maximum === "number" && value > s2.maximum) {
|
|
3240
|
+
issues.push({
|
|
3241
|
+
path,
|
|
3242
|
+
message: `must be <= ${s2.maximum}`
|
|
3243
|
+
});
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
if (Array.isArray(value)) {
|
|
3247
|
+
if (typeof s2.minItems === "number" && value.length < s2.minItems) {
|
|
3248
|
+
issues.push({
|
|
3249
|
+
path,
|
|
3250
|
+
message: `must have at least ${s2.minItems} items`
|
|
3251
|
+
});
|
|
3252
|
+
}
|
|
3253
|
+
if (typeof s2.maxItems === "number" && value.length > s2.maxItems) {
|
|
3254
|
+
issues.push({
|
|
3255
|
+
path,
|
|
3256
|
+
message: `must have at most ${s2.maxItems} items`
|
|
3257
|
+
});
|
|
3258
|
+
}
|
|
3259
|
+
if (s2.items !== void 0 && !Array.isArray(s2.items)) {
|
|
3260
|
+
value.forEach((item, index) => {
|
|
3261
|
+
check(s2.items, item, [
|
|
3262
|
+
...path,
|
|
3263
|
+
index
|
|
3264
|
+
], root, issues, depth + 1);
|
|
3265
|
+
});
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
if (matchesType("object", value)) {
|
|
3269
|
+
const record2 = value;
|
|
3270
|
+
const properties = typeof s2.properties === "object" && s2.properties !== null ? s2.properties : {};
|
|
3271
|
+
if (Array.isArray(s2.required)) {
|
|
3272
|
+
for (const key of s2.required) {
|
|
3273
|
+
if (record2[key] === void 0) {
|
|
3274
|
+
issues.push({
|
|
3275
|
+
path: [
|
|
3276
|
+
...path,
|
|
3277
|
+
key
|
|
3278
|
+
],
|
|
3279
|
+
message: "is required"
|
|
3280
|
+
});
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
for (const [key, entry] of Object.entries(record2)) {
|
|
3285
|
+
if (key in properties) {
|
|
3286
|
+
if (entry !== void 0) {
|
|
3287
|
+
check(properties[key], entry, [
|
|
3288
|
+
...path,
|
|
3289
|
+
key
|
|
3290
|
+
], root, issues, depth + 1);
|
|
3291
|
+
}
|
|
3292
|
+
} else if (s2.additionalProperties === false) {
|
|
3293
|
+
issues.push({
|
|
3294
|
+
path: [
|
|
3295
|
+
...path,
|
|
3296
|
+
key
|
|
3297
|
+
],
|
|
3298
|
+
message: "is not a known property"
|
|
3299
|
+
});
|
|
3300
|
+
} else if (typeof s2.additionalProperties === "object" && s2.additionalProperties !== null) {
|
|
3301
|
+
check(s2.additionalProperties, entry, [
|
|
3302
|
+
...path,
|
|
3303
|
+
key
|
|
3304
|
+
], root, issues, depth + 1);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
if (Array.isArray(s2.allOf)) {
|
|
3309
|
+
for (const sub of s2.allOf) check(sub, value, path, root, issues, depth + 1);
|
|
3310
|
+
}
|
|
3311
|
+
if (Array.isArray(s2.anyOf) || Array.isArray(s2.oneOf)) {
|
|
3312
|
+
const options = Array.isArray(s2.anyOf) ? s2.anyOf : s2.oneOf;
|
|
3313
|
+
const passing = options.filter((sub) => {
|
|
3314
|
+
const nested = [];
|
|
3315
|
+
check(sub, value, path, root, nested, depth + 1);
|
|
3316
|
+
return nested.length === 0;
|
|
3317
|
+
}).length;
|
|
3318
|
+
if (Array.isArray(s2.anyOf) ? passing === 0 : passing !== 1) {
|
|
3319
|
+
issues.push({
|
|
3320
|
+
path,
|
|
3321
|
+
message: Array.isArray(s2.anyOf) ? "does not match any allowed shape" : "must match exactly one allowed shape"
|
|
3322
|
+
});
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
if (s2.not !== void 0) {
|
|
3326
|
+
const nested = [];
|
|
3327
|
+
check(s2.not, value, path, root, nested, depth + 1);
|
|
3328
|
+
if (nested.length === 0) {
|
|
3329
|
+
issues.push({
|
|
3330
|
+
path,
|
|
3331
|
+
message: "matches a shape that is not allowed"
|
|
3332
|
+
});
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3336
|
+
__name(check, "check");
|
|
3337
|
+
|
|
3338
|
+
// src/genui/catalog.ts
|
|
3339
|
+
var COMPONENT_NAME = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
|
|
3340
|
+
function defineComponent(definition) {
|
|
3341
|
+
if (!COMPONENT_NAME.test(definition.name)) {
|
|
3342
|
+
throw new Error(`genui: component name "${definition.name}" must be letters and digits, starting with a letter (e.g. DataTable)`);
|
|
3343
|
+
}
|
|
3344
|
+
if (definition.version !== void 0 && (!Number.isSafeInteger(definition.version) || definition.version <= 0)) throw new RangeError("genui: component version must be a positive safe integer");
|
|
3345
|
+
if (definition.fallbackText !== void 0 && typeof definition.fallbackText !== "function") throw new TypeError("genui: fallbackText must be a function");
|
|
3346
|
+
return definition;
|
|
3347
|
+
}
|
|
3348
|
+
__name(defineComponent, "defineComponent");
|
|
3349
|
+
function defineCatalog(components, options = {}) {
|
|
3350
|
+
const byName = /* @__PURE__ */ new Map();
|
|
3351
|
+
for (const component of components) {
|
|
3352
|
+
defineComponent(component);
|
|
3353
|
+
if (byName.has(component.name)) {
|
|
3354
|
+
throw new Error(`genui: component "${component.name}" is defined twice in one catalog`);
|
|
3355
|
+
}
|
|
3356
|
+
byName.set(component.name, component);
|
|
3357
|
+
}
|
|
3358
|
+
return buildCatalog(byName, options.jsonSchemaValidator ?? builtinJsonSchemaValidator);
|
|
3359
|
+
}
|
|
3360
|
+
__name(defineCatalog, "defineCatalog");
|
|
3361
|
+
function buildCatalog(byName, validator) {
|
|
3362
|
+
const list = Object.freeze([
|
|
3363
|
+
...byName.values()
|
|
3364
|
+
]);
|
|
3365
|
+
return {
|
|
3366
|
+
components: list,
|
|
3367
|
+
validator,
|
|
3368
|
+
get: /* @__PURE__ */ __name((name) => byName.get(name), "get"),
|
|
3369
|
+
has: /* @__PURE__ */ __name((name) => byName.has(name), "has"),
|
|
3370
|
+
modelComponents: /* @__PURE__ */ __name(() => list.filter((component) => component.internal !== true), "modelComponents"),
|
|
3371
|
+
async validate(component, props) {
|
|
3372
|
+
const definition = byName.get(component);
|
|
3373
|
+
if (definition === void 0) {
|
|
3374
|
+
return {
|
|
3375
|
+
ok: false,
|
|
3376
|
+
issues: [
|
|
3377
|
+
{
|
|
3378
|
+
path: [],
|
|
3379
|
+
message: `unknown component "${component}"`
|
|
3380
|
+
}
|
|
3381
|
+
]
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
const result2 = await validateProps(definition.outputProps ?? definition.props, props, validator);
|
|
3385
|
+
return result2;
|
|
3386
|
+
},
|
|
3387
|
+
validateSync(component, props) {
|
|
3388
|
+
const definition = byName.get(component);
|
|
3389
|
+
if (definition === void 0) {
|
|
3390
|
+
return {
|
|
3391
|
+
ok: false,
|
|
3392
|
+
issues: [
|
|
3393
|
+
{
|
|
3394
|
+
path: [],
|
|
3395
|
+
message: `unknown component "${component}"`
|
|
3396
|
+
}
|
|
3397
|
+
]
|
|
3398
|
+
};
|
|
3399
|
+
}
|
|
3400
|
+
return validatePropsSync(definition.outputProps ?? definition.props, props, validator);
|
|
3401
|
+
},
|
|
3402
|
+
jsonSchemaFor(component) {
|
|
3403
|
+
const definition = byName.get(component);
|
|
3404
|
+
return definition === void 0 ? void 0 : toJsonSchema(definition.outputProps ?? definition.props);
|
|
3405
|
+
},
|
|
3406
|
+
extend(more) {
|
|
3407
|
+
const next = new Map(byName);
|
|
3408
|
+
for (const component of more) {
|
|
3409
|
+
defineComponent(component);
|
|
3410
|
+
next.set(component.name, component);
|
|
3411
|
+
}
|
|
3412
|
+
return buildCatalog(next, validator);
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
__name(buildCatalog, "buildCatalog");
|
|
3417
|
+
|
|
3418
|
+
// src/genui/tree.ts
|
|
3419
|
+
var GENUI_TREE_COMPONENT = "genui:tree";
|
|
3420
|
+
async function validateTree(catalog, tree, limits = {}, phase = "output") {
|
|
3421
|
+
const maxDepth = limits.maxDepth ?? 12;
|
|
3422
|
+
const maxNodes = limits.maxNodes ?? 200;
|
|
3423
|
+
const issues = [];
|
|
3424
|
+
let nodes = 0;
|
|
3425
|
+
const visit = /* @__PURE__ */ __name(async (node, path, depth) => {
|
|
3426
|
+
nodes += 1;
|
|
3427
|
+
if (nodes > maxNodes) {
|
|
3428
|
+
if (nodes === maxNodes + 1) {
|
|
3429
|
+
issues.push({
|
|
3430
|
+
path,
|
|
3431
|
+
message: `the tree has more than ${maxNodes} elements`
|
|
3432
|
+
});
|
|
3433
|
+
}
|
|
3434
|
+
return void 0;
|
|
3435
|
+
}
|
|
3436
|
+
if (depth > maxDepth) {
|
|
3437
|
+
issues.push({
|
|
3438
|
+
path,
|
|
3439
|
+
message: `the tree is nested deeper than ${maxDepth} levels`
|
|
3440
|
+
});
|
|
3441
|
+
return void 0;
|
|
3442
|
+
}
|
|
3443
|
+
if (typeof node !== "object" || node === null || Array.isArray(node)) {
|
|
3444
|
+
issues.push({
|
|
3445
|
+
path,
|
|
3446
|
+
message: "must be an element object { type, props, children? }"
|
|
3447
|
+
});
|
|
3448
|
+
return void 0;
|
|
3449
|
+
}
|
|
3450
|
+
const element = node;
|
|
3451
|
+
if (typeof element.type !== "string") {
|
|
3452
|
+
issues.push({
|
|
3453
|
+
path: [
|
|
3454
|
+
...path,
|
|
3455
|
+
"type"
|
|
3456
|
+
],
|
|
3457
|
+
message: "must be a component name"
|
|
3458
|
+
});
|
|
3459
|
+
return void 0;
|
|
3460
|
+
}
|
|
3461
|
+
const definition = catalog.get(element.type);
|
|
3462
|
+
if (definition === void 0 || definition.internal === true) {
|
|
3463
|
+
issues.push({
|
|
3464
|
+
path: [
|
|
3465
|
+
...path,
|
|
3466
|
+
"type"
|
|
3467
|
+
],
|
|
3468
|
+
message: `unknown component "${element.type}" (allowed: ${catalog.modelComponents().map((component) => component.name).join(", ")})`
|
|
3469
|
+
});
|
|
3470
|
+
return void 0;
|
|
3471
|
+
}
|
|
3472
|
+
const validated = phase === "input" ? await validateProps(definition.props, element.props ?? {}, catalog.validator) : await catalog.validate(element.type, element.props ?? {});
|
|
3473
|
+
let props = {};
|
|
3474
|
+
if (!validated.ok) {
|
|
3475
|
+
for (const issue4 of validated.issues) {
|
|
3476
|
+
issues.push({
|
|
3477
|
+
path: [
|
|
3478
|
+
...path,
|
|
3479
|
+
"props",
|
|
3480
|
+
...issue4.path
|
|
3481
|
+
],
|
|
3482
|
+
message: issue4.message
|
|
3483
|
+
});
|
|
3484
|
+
}
|
|
3485
|
+
} else {
|
|
3486
|
+
props = validated.value;
|
|
3487
|
+
}
|
|
3488
|
+
const rawChildren = parseChildrenIfStringified(element.children);
|
|
3489
|
+
if (rawChildren === void 0 || rawChildren === null) {
|
|
3490
|
+
return {
|
|
3491
|
+
type: element.type,
|
|
3492
|
+
props
|
|
3493
|
+
};
|
|
3494
|
+
}
|
|
3495
|
+
if (!Array.isArray(rawChildren)) {
|
|
3496
|
+
issues.push({
|
|
3497
|
+
path: [
|
|
3498
|
+
...path,
|
|
3499
|
+
"children"
|
|
3500
|
+
],
|
|
3501
|
+
message: "must be an array of elements (a literal array, not a string)"
|
|
3502
|
+
});
|
|
3503
|
+
return void 0;
|
|
3504
|
+
}
|
|
3505
|
+
if (rawChildren.length > 0 && definition.children !== true) {
|
|
3506
|
+
issues.push({
|
|
3507
|
+
path: [
|
|
3508
|
+
...path,
|
|
3509
|
+
"children"
|
|
3510
|
+
],
|
|
3511
|
+
message: `${element.type} does not take children`
|
|
3512
|
+
});
|
|
3513
|
+
return void 0;
|
|
3514
|
+
}
|
|
3515
|
+
const children = [];
|
|
3516
|
+
for (const [index, child] of rawChildren.entries()) {
|
|
3517
|
+
const next = await visit(child, [
|
|
3518
|
+
...path,
|
|
3519
|
+
"children",
|
|
3520
|
+
index
|
|
3521
|
+
], depth + 1);
|
|
3522
|
+
if (next !== void 0) {
|
|
3523
|
+
children.push(next);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
return children.length > 0 ? {
|
|
3527
|
+
type: element.type,
|
|
3528
|
+
props,
|
|
3529
|
+
children
|
|
3530
|
+
} : {
|
|
3531
|
+
type: element.type,
|
|
3532
|
+
props
|
|
3533
|
+
};
|
|
3534
|
+
}, "visit");
|
|
3535
|
+
const root = await visit(tree, [], 1);
|
|
3536
|
+
return issues.length > 0 || root === void 0 ? {
|
|
3537
|
+
ok: false,
|
|
3538
|
+
issues: issues.length > 0 ? issues : [
|
|
3539
|
+
{
|
|
3540
|
+
path: [],
|
|
3541
|
+
message: "is invalid"
|
|
3542
|
+
}
|
|
3543
|
+
]
|
|
3544
|
+
} : {
|
|
3545
|
+
ok: true,
|
|
3546
|
+
value: root
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
__name(validateTree, "validateTree");
|
|
3550
|
+
function parseChildrenIfStringified(value) {
|
|
3551
|
+
if (typeof value !== "string") return value;
|
|
3552
|
+
const trimmed = value.trim();
|
|
3553
|
+
if (!trimmed.startsWith("[")) return value;
|
|
3554
|
+
return leadingJsonArray(trimmed) ?? value;
|
|
3555
|
+
}
|
|
3556
|
+
__name(parseChildrenIfStringified, "parseChildrenIfStringified");
|
|
3557
|
+
function leadingJsonArray(text) {
|
|
3558
|
+
let depth = 0;
|
|
3559
|
+
let inString = false;
|
|
3560
|
+
let escaped = false;
|
|
3561
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
3562
|
+
const char = text[index];
|
|
3563
|
+
if (inString) {
|
|
3564
|
+
if (escaped) escaped = false;
|
|
3565
|
+
else if (char === "\\") escaped = true;
|
|
3566
|
+
else if (char === '"') inString = false;
|
|
3567
|
+
continue;
|
|
3568
|
+
}
|
|
3569
|
+
if (char === '"') inString = true;
|
|
3570
|
+
else if (char === "[" || char === "{") depth += 1;
|
|
3571
|
+
else if (char === "]" || char === "}") {
|
|
3572
|
+
depth -= 1;
|
|
3573
|
+
if (depth === 0) {
|
|
3574
|
+
try {
|
|
3575
|
+
const parsed = JSON.parse(text.slice(0, index + 1));
|
|
3576
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
3577
|
+
} catch {
|
|
3578
|
+
return void 0;
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
return void 0;
|
|
3584
|
+
}
|
|
3585
|
+
__name(leadingJsonArray, "leadingJsonArray");
|
|
3586
|
+
|
|
3587
|
+
// src/genui/text.ts
|
|
3588
|
+
function componentToText(catalog, component, props) {
|
|
3589
|
+
if (component === GENUI_TREE_COMPONENT) {
|
|
3590
|
+
const root = props.root;
|
|
3591
|
+
return root === void 0 ? "" : treeToText(catalog, root);
|
|
3592
|
+
}
|
|
3593
|
+
const fallback = catalog.get(component)?.fallbackText;
|
|
3594
|
+
if (fallback !== void 0) {
|
|
3595
|
+
try {
|
|
3596
|
+
const text = fallback(props);
|
|
3597
|
+
if (typeof text === "string" && text.trim().length > 0) return text;
|
|
3598
|
+
} catch {
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
return jsonBlock(props);
|
|
3602
|
+
}
|
|
3603
|
+
__name(componentToText, "componentToText");
|
|
3604
|
+
function treeToText(catalog, root) {
|
|
3605
|
+
const out = [];
|
|
3606
|
+
const visit = /* @__PURE__ */ __name((node, depth) => {
|
|
3607
|
+
if (depth > 32) return;
|
|
3608
|
+
const definition = catalog.get(node.type);
|
|
3609
|
+
if (definition?.fallbackText !== void 0) {
|
|
3610
|
+
try {
|
|
3611
|
+
const text = definition.fallbackText(node.props);
|
|
3612
|
+
out.push(typeof text === "string" && text.trim().length > 0 ? text : jsonBlock(node.props));
|
|
3613
|
+
} catch {
|
|
3614
|
+
out.push(jsonBlock(node.props));
|
|
3615
|
+
}
|
|
3616
|
+
} else if (definition?.children !== true) {
|
|
3617
|
+
out.push(jsonBlock(node.props));
|
|
3618
|
+
}
|
|
3619
|
+
for (const child of node.children ?? []) visit(child, depth + 1);
|
|
3620
|
+
}, "visit");
|
|
3621
|
+
visit(root, 0);
|
|
3622
|
+
return out.filter((line) => line.trim().length > 0).join("\n");
|
|
3623
|
+
}
|
|
3624
|
+
__name(treeToText, "treeToText");
|
|
3625
|
+
function jsonBlock(props) {
|
|
3626
|
+
const title = typeof props.title === "string" && props.title.length > 0 ? `*${props.title}*
|
|
3627
|
+
` : "";
|
|
3628
|
+
return `${title}\`\`\`
|
|
3629
|
+
${JSON.stringify(props, null, 2)}
|
|
3630
|
+
\`\`\``;
|
|
3631
|
+
}
|
|
3632
|
+
__name(jsonBlock, "jsonBlock");
|
|
3633
|
+
|
|
3634
|
+
// src/genui/capabilities.ts
|
|
3635
|
+
function validateUiCapabilities(value) {
|
|
3636
|
+
if (!record(value) || Object.keys(value).some((key) => key !== "components") || !Array.isArray(value.components)) throw new TypeError("Invalid UI capabilities");
|
|
3637
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3638
|
+
const components = value.components.map((component) => {
|
|
3639
|
+
if (!record(component) || Object.keys(component).some((key) => key !== "name" && key !== "version") || typeof component.name !== "string" || !COMPONENT_NAME.test(component.name) || !Number.isSafeInteger(component.version) || Number(component.version) <= 0 || seen.has(component.name)) throw new TypeError("Invalid UI component capability");
|
|
3640
|
+
seen.add(component.name);
|
|
3641
|
+
return {
|
|
3642
|
+
name: component.name,
|
|
3643
|
+
version: Number(component.version)
|
|
3644
|
+
};
|
|
3645
|
+
});
|
|
3646
|
+
return {
|
|
3647
|
+
components
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
__name(validateUiCapabilities, "validateUiCapabilities");
|
|
3651
|
+
function record(value) {
|
|
3652
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3653
|
+
}
|
|
3654
|
+
__name(record, "record");
|
|
3655
|
+
function negotiateCatalog(catalog, capabilities) {
|
|
3656
|
+
if (capabilities === void 0) return catalog;
|
|
3657
|
+
const supported = validateUiCapabilities(capabilities).components;
|
|
3658
|
+
return defineCatalog(catalog.components.filter((component) => supported.some((entry) => entry.name === component.name && entry.version === (component.version ?? 1))), {
|
|
3659
|
+
jsonSchemaValidator: catalog.validator
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
__name(negotiateCatalog, "negotiateCatalog");
|
|
3663
|
+
async function prepareUiEmission(catalog, capabilities, component, props, version) {
|
|
3664
|
+
const drawable = negotiateCatalog(catalog, capabilities);
|
|
3665
|
+
if (component === GENUI_TREE_COMPONENT) {
|
|
3666
|
+
if (version !== void 0 && version !== 1) throw new Error("Invalid UI tree version");
|
|
3667
|
+
const validated2 = await validateTree(catalog, props.root);
|
|
3668
|
+
if (!validated2.ok) throw new Error(`Invalid UI tree: ${formatIssues(validated2.issues)}`);
|
|
3669
|
+
const supported = /* @__PURE__ */ __name((node) => drawable.has(node.type) && (node.children ?? []).every(supported), "supported");
|
|
3670
|
+
const versions = /* @__PURE__ */ new Map();
|
|
3671
|
+
const collectVersions = /* @__PURE__ */ __name((node) => {
|
|
3672
|
+
versions.set(node.type, catalog.get(node.type)?.version ?? 1);
|
|
3673
|
+
for (const child of node.children ?? []) collectVersions(child);
|
|
3674
|
+
}, "collectVersions");
|
|
3675
|
+
collectVersions(validated2.value);
|
|
3676
|
+
return supported(validated2.value) ? {
|
|
3677
|
+
kind: "ui",
|
|
3678
|
+
component,
|
|
3679
|
+
props: {
|
|
3680
|
+
root: validated2.value
|
|
3681
|
+
},
|
|
3682
|
+
version: 1,
|
|
3683
|
+
fallbackText: treeToText(catalog, validated2.value),
|
|
3684
|
+
componentVersions: Object.fromEntries(versions)
|
|
3685
|
+
} : {
|
|
3686
|
+
kind: "text",
|
|
3687
|
+
text: treeToText(catalog, validated2.value)
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
const definition = catalog.get(component);
|
|
3691
|
+
if (definition === void 0) throw new Error(`Unknown UI component "${component}"`);
|
|
3692
|
+
const currentVersion = definition.version ?? 1;
|
|
3693
|
+
if (version !== void 0 && version !== currentVersion) throw new Error(`Invalid UI component version for "${component}"`);
|
|
3694
|
+
const validated = await catalog.validate(component, props);
|
|
3695
|
+
if (!validated.ok) throw new Error(`Invalid UI props: ${formatIssues(validated.issues)}`);
|
|
3696
|
+
return drawable.has(component) ? {
|
|
3697
|
+
kind: "ui",
|
|
3698
|
+
component,
|
|
3699
|
+
props: validated.value,
|
|
3700
|
+
version: currentVersion,
|
|
3701
|
+
fallbackText: componentToText(catalog, component, validated.value)
|
|
3702
|
+
} : {
|
|
3703
|
+
kind: "text",
|
|
3704
|
+
text: componentToText(catalog, component, validated.value)
|
|
3705
|
+
};
|
|
3706
|
+
}
|
|
3707
|
+
__name(prepareUiEmission, "prepareUiEmission");
|
|
3708
|
+
|
|
3709
|
+
// src/action-proposal-transitions.ts
|
|
3710
|
+
function checkTime(value) {
|
|
3711
|
+
if (!Number.isSafeInteger(value)) throw new RangeError("Action proposal timestamps must be safe integer milliseconds");
|
|
3712
|
+
}
|
|
3713
|
+
__name(checkTime, "checkTime");
|
|
3714
|
+
function checkString(value) {
|
|
3715
|
+
if (typeof value !== "string" || value.length === 0) throw new TypeError("Action proposal identifiers must be nonempty strings");
|
|
3716
|
+
}
|
|
3717
|
+
__name(checkString, "checkString");
|
|
3718
|
+
function validateActionProposalCreation(input) {
|
|
3719
|
+
const allowed = [
|
|
3720
|
+
"id",
|
|
3721
|
+
"tenantRef",
|
|
3722
|
+
"actorRef",
|
|
3723
|
+
"threadId",
|
|
3724
|
+
"originRunId",
|
|
3725
|
+
"originMessageId",
|
|
3726
|
+
"originToolCallId",
|
|
3727
|
+
"toolName",
|
|
3728
|
+
"input",
|
|
3729
|
+
"preparationInput",
|
|
3730
|
+
"executionContext",
|
|
3731
|
+
"confirmation",
|
|
3732
|
+
"approver",
|
|
3733
|
+
"expiresAt",
|
|
3734
|
+
"idempotencyKey",
|
|
3735
|
+
"replacementKey"
|
|
3736
|
+
];
|
|
3737
|
+
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("Unknown action proposal creation field");
|
|
3738
|
+
for (const key of [
|
|
3739
|
+
"id",
|
|
3740
|
+
"actorRef",
|
|
3741
|
+
"threadId",
|
|
3742
|
+
"originRunId",
|
|
3743
|
+
"originMessageId",
|
|
3744
|
+
"originToolCallId",
|
|
3745
|
+
"toolName",
|
|
3746
|
+
"approver",
|
|
3747
|
+
"idempotencyKey"
|
|
3748
|
+
]) checkString(input[key]);
|
|
3749
|
+
if (input.tenantRef !== null && typeof input.tenantRef !== "string") throw new TypeError("tenantRef must be an explicit string or null");
|
|
3750
|
+
for (const value of [
|
|
3751
|
+
input.id,
|
|
3752
|
+
input.actorRef,
|
|
3753
|
+
input.threadId,
|
|
3754
|
+
input.tenantRef
|
|
3755
|
+
]) {
|
|
3756
|
+
if (value !== null && value.length > 255) throw new RangeError("Action proposal id and scope must fit 255 UTF-16 code units");
|
|
3757
|
+
}
|
|
3758
|
+
if (input.replacementKey !== void 0) {
|
|
3759
|
+
checkString(input.replacementKey);
|
|
3760
|
+
if (input.replacementKey.length > 255) throw new RangeError("replacementKey must fit 255 UTF-16 code units");
|
|
3761
|
+
}
|
|
3762
|
+
if (Object.hasOwn(input, "executionContext")) {
|
|
3763
|
+
const context = input.executionContext;
|
|
3764
|
+
if (context === null || typeof context !== "object" || Array.isArray(context)) throw new TypeError("executionContext must be a JSON object");
|
|
3765
|
+
const allowedContext = [
|
|
3766
|
+
"agentName",
|
|
3767
|
+
"persona",
|
|
3768
|
+
"requestId",
|
|
3769
|
+
"pageContext",
|
|
3770
|
+
"uiCapabilities"
|
|
3771
|
+
];
|
|
3772
|
+
if (Object.keys(context).some((key) => !allowedContext.includes(key))) throw new TypeError("Unknown execution context field");
|
|
3773
|
+
checkString(context.requestId);
|
|
3774
|
+
if (Object.hasOwn(context, "uiCapabilities")) validateUiCapabilities(context.uiCapabilities);
|
|
3775
|
+
if (Object.hasOwn(context, "agentName")) checkString(context.agentName);
|
|
3776
|
+
if (Object.hasOwn(context, "persona")) checkString(context.persona);
|
|
3777
|
+
if (Object.hasOwn(context, "pageContext")) {
|
|
3778
|
+
const page = context.pageContext;
|
|
3779
|
+
if (page === null || typeof page !== "object" || Array.isArray(page)) throw new TypeError("pageContext must be a JSON object");
|
|
3780
|
+
if (Object.hasOwn(page, "kind") && typeof page.kind !== "string") throw new TypeError("pageContext.kind must be a string");
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
if (input.expiresAt !== null) checkTime(input.expiresAt);
|
|
3784
|
+
checkString(input.confirmation?.title);
|
|
3785
|
+
checkString(input.confirmation?.verb);
|
|
3786
|
+
canonicalActionProposalJson(input);
|
|
3787
|
+
}
|
|
3788
|
+
__name(validateActionProposalCreation, "validateActionProposalCreation");
|
|
3789
|
+
function validateActionProposalListQuery(query = {}) {
|
|
3790
|
+
const limit = query.limit === void 0 ? 100 : query.limit;
|
|
3791
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 1e3) throw new RangeError("limit must be an integer from 1 to 1000");
|
|
3792
|
+
if (query.decision !== void 0 && ![
|
|
3793
|
+
"pending",
|
|
3794
|
+
"approved",
|
|
3795
|
+
"rejected",
|
|
3796
|
+
"expired",
|
|
3797
|
+
"superseded"
|
|
3798
|
+
].includes(query.decision)) throw new TypeError("Unsupported action proposal list decision");
|
|
3799
|
+
if (query.after !== void 0) {
|
|
3800
|
+
const after = query.after;
|
|
3801
|
+
if (typeof after !== "object" || after === null || Array.isArray(after) || Object.keys(after).some((key) => key !== "createdAt" && key !== "id")) throw new TypeError("Invalid action proposal cursor");
|
|
3802
|
+
checkTime(after.createdAt);
|
|
3803
|
+
checkString(after.id);
|
|
3804
|
+
if (after.id.length > 255) throw new TypeError("Action proposal cursor id is too long");
|
|
3805
|
+
}
|
|
3806
|
+
return limit;
|
|
3807
|
+
}
|
|
3808
|
+
__name(validateActionProposalListQuery, "validateActionProposalListQuery");
|
|
3809
|
+
function canonicalActionProposalJson(value) {
|
|
3810
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
3811
|
+
const sort = /* @__PURE__ */ __name((item) => {
|
|
3812
|
+
if (item === null || typeof item === "string" || typeof item === "boolean") return item;
|
|
3813
|
+
if (typeof item === "number" && Number.isFinite(item)) return item;
|
|
3814
|
+
if (typeof item !== "object" || item === null || ancestors.has(item)) throw new TypeError("Action proposals require finite, acyclic JSON values");
|
|
3815
|
+
const prototype = Object.getPrototypeOf(item);
|
|
3816
|
+
if (!Array.isArray(item) && prototype !== Object.prototype && prototype !== null) throw new TypeError("Action proposals require plain JSON objects");
|
|
3817
|
+
ancestors.add(item);
|
|
3818
|
+
const sorted = Array.isArray(item) ? Array.from(item, sort) : Object.fromEntries(Object.keys(item).sort().map((key) => [
|
|
3819
|
+
key,
|
|
3820
|
+
sort(item[key])
|
|
3821
|
+
]));
|
|
3822
|
+
ancestors.delete(item);
|
|
3823
|
+
return sorted;
|
|
3824
|
+
}, "sort");
|
|
3825
|
+
return JSON.stringify(sort(value));
|
|
3826
|
+
}
|
|
3827
|
+
__name(canonicalActionProposalJson, "canonicalActionProposalJson");
|
|
3828
|
+
function snapshotActionProposal(value) {
|
|
3829
|
+
return JSON.parse(canonicalActionProposalJson(value));
|
|
3830
|
+
}
|
|
3831
|
+
__name(snapshotActionProposal, "snapshotActionProposal");
|
|
3832
|
+
function actionProposalScopeMatches(row2, scope) {
|
|
3833
|
+
return row2.tenantRef === scope.tenantRef && row2.actorRef === scope.actorRef && row2.threadId === scope.threadId;
|
|
3834
|
+
}
|
|
3835
|
+
__name(actionProposalScopeMatches, "actionProposalScopeMatches");
|
|
3836
|
+
function initialActionProposal(input, now) {
|
|
3837
|
+
validateActionProposalCreation(input);
|
|
3838
|
+
checkTime(now);
|
|
3839
|
+
return snapshotActionProposal({
|
|
3840
|
+
...input,
|
|
3841
|
+
decision: "pending",
|
|
3842
|
+
decisionAudit: null,
|
|
3843
|
+
execution: null,
|
|
3844
|
+
createdAt: now,
|
|
3845
|
+
updatedAt: now
|
|
3846
|
+
});
|
|
3847
|
+
}
|
|
3848
|
+
__name(initialActionProposal, "initialActionProposal");
|
|
3849
|
+
function actionProposalCreationMatches(row2, input) {
|
|
3850
|
+
validateActionProposalCreation(input);
|
|
3851
|
+
const { decision: _decision, decisionAudit: _audit, execution: _execution, createdAt: _created, updatedAt: _updated, supersededBy: _supersededBy, outcome: _outcome, outcomeDelivery: _delivery, ...original } = row2;
|
|
3852
|
+
return canonicalActionProposalJson(original) === canonicalActionProposalJson(input);
|
|
3853
|
+
}
|
|
3854
|
+
__name(actionProposalCreationMatches, "actionProposalCreationMatches");
|
|
3855
|
+
function result(status, proposal) {
|
|
3856
|
+
return {
|
|
3857
|
+
status,
|
|
3858
|
+
proposal: snapshotActionProposal(proposal)
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
__name(result, "result");
|
|
3862
|
+
function transitionActionProposalDecision(row2, command, now) {
|
|
3863
|
+
checkTime(now);
|
|
3864
|
+
if (![
|
|
3865
|
+
"approved",
|
|
3866
|
+
"rejected",
|
|
3867
|
+
"expired"
|
|
3868
|
+
].includes(command.decision)) throw new TypeError("Unsupported action proposal decision");
|
|
3869
|
+
checkString(command.actorRef);
|
|
3870
|
+
checkString(command.via);
|
|
3871
|
+
if (command.reason !== void 0 && typeof command.reason !== "string") throw new TypeError("reason must be a string");
|
|
3872
|
+
if (command.remember !== void 0 && typeof command.remember !== "boolean") throw new TypeError("remember must be a boolean");
|
|
3873
|
+
if (row2.decision !== "pending") {
|
|
3874
|
+
return result(row2.decision === command.decision ? "unchanged" : row2.decision === "expired" ? "expired" : "conflict", row2);
|
|
3875
|
+
}
|
|
3876
|
+
const next = snapshotActionProposal(row2);
|
|
3877
|
+
if (row2.expiresAt !== null && now >= row2.expiresAt) {
|
|
3878
|
+
next.decision = "expired";
|
|
3879
|
+
next.decisionAudit = {
|
|
3880
|
+
actorRef: "system",
|
|
3881
|
+
via: "expiry",
|
|
3882
|
+
at: now
|
|
3883
|
+
};
|
|
3884
|
+
next.updatedAt = now;
|
|
3885
|
+
return result(command.decision === "expired" ? "applied" : "expired", attachActionProposalOutcome(next, now));
|
|
3886
|
+
}
|
|
3887
|
+
if (command.decision === "expired") return result("conflict", row2);
|
|
3888
|
+
const { decision, ...audit } = command;
|
|
3889
|
+
next.decision = decision;
|
|
3890
|
+
next.decisionAudit = {
|
|
3891
|
+
actorRef: audit.actorRef,
|
|
3892
|
+
via: audit.via,
|
|
3893
|
+
at: now,
|
|
3894
|
+
...audit.reason === void 0 ? {} : {
|
|
3895
|
+
reason: audit.reason
|
|
3896
|
+
},
|
|
3897
|
+
...audit.remember === void 0 ? {} : {
|
|
3898
|
+
remember: audit.remember
|
|
3899
|
+
}
|
|
3900
|
+
};
|
|
3901
|
+
next.updatedAt = now;
|
|
3902
|
+
if (decision === "approved") next.execution = {
|
|
3903
|
+
status: "queued",
|
|
3904
|
+
generation: 0,
|
|
3905
|
+
lease: null
|
|
3906
|
+
};
|
|
3907
|
+
return result("applied", decision === "approved" ? next : attachActionProposalOutcome(next, now));
|
|
3908
|
+
}
|
|
3909
|
+
__name(transitionActionProposalDecision, "transitionActionProposalDecision");
|
|
3910
|
+
function checkLeaseMs(leaseMs, now) {
|
|
3911
|
+
checkTime(now);
|
|
3912
|
+
if (!Number.isSafeInteger(leaseMs) || leaseMs <= 0 || !Number.isSafeInteger(now + leaseMs)) throw new RangeError("leaseMs must be finite and positive");
|
|
3913
|
+
}
|
|
3914
|
+
__name(checkLeaseMs, "checkLeaseMs");
|
|
3915
|
+
function transitionActionProposalClaim(row2, command, now, token) {
|
|
3916
|
+
checkLeaseMs(command.leaseMs, now);
|
|
3917
|
+
checkString(command.workerId);
|
|
3918
|
+
checkString(token);
|
|
3919
|
+
const execution = row2.execution;
|
|
3920
|
+
if (row2.decision !== "approved" || !execution || execution.status !== "queued" && !(execution.status === "executing" && execution.lease && now >= execution.lease.expiresAt)) return result("conflict", row2);
|
|
3921
|
+
const next = snapshotActionProposal(row2);
|
|
3922
|
+
const generation = execution.generation + 1;
|
|
3923
|
+
next.execution = {
|
|
3924
|
+
status: "executing",
|
|
3925
|
+
generation,
|
|
3926
|
+
lease: {
|
|
3927
|
+
token,
|
|
3928
|
+
generation,
|
|
3929
|
+
workerId: command.workerId,
|
|
3930
|
+
expiresAt: now + command.leaseMs
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
next.updatedAt = now;
|
|
3934
|
+
return result("applied", next);
|
|
3935
|
+
}
|
|
3936
|
+
__name(transitionActionProposalClaim, "transitionActionProposalClaim");
|
|
3937
|
+
function leaseStatus(row2, command, now) {
|
|
3938
|
+
checkTime(now);
|
|
3939
|
+
checkString(command.token);
|
|
3940
|
+
if (!Number.isSafeInteger(command.generation) || command.generation < 1) throw new RangeError("Invalid lease generation");
|
|
3941
|
+
const work = row2.execution;
|
|
3942
|
+
if (row2.decision !== "approved" || work?.status !== "executing" || !work.lease || work.generation !== command.generation || work.lease.generation !== command.generation || work.lease.token !== command.token) return "conflict";
|
|
3943
|
+
return now >= work.lease.expiresAt ? "expired" : "valid";
|
|
3944
|
+
}
|
|
3945
|
+
__name(leaseStatus, "leaseStatus");
|
|
3946
|
+
function transitionActionProposalLease(row2, command, now) {
|
|
3947
|
+
checkLeaseMs(command.leaseMs, now);
|
|
3948
|
+
const status = leaseStatus(row2, command, now);
|
|
3949
|
+
if (status !== "valid") return result(status, row2);
|
|
3950
|
+
const next = snapshotActionProposal(row2);
|
|
3951
|
+
if (next.execution?.lease) next.execution.lease.expiresAt = Math.max(next.execution.lease.expiresAt, now + command.leaseMs);
|
|
3952
|
+
next.updatedAt = now;
|
|
3953
|
+
return result("applied", next);
|
|
3954
|
+
}
|
|
3955
|
+
__name(transitionActionProposalLease, "transitionActionProposalLease");
|
|
3956
|
+
function transitionActionProposalSettlement(row2, command, now) {
|
|
3957
|
+
checkTime(now);
|
|
3958
|
+
if (command.status !== "succeeded" && command.status !== "failed") throw new TypeError("Unsupported settlement status");
|
|
3959
|
+
if (command.status === "succeeded" && command.error !== void 0 || command.status === "failed" && (typeof command.error !== "string" || command.result !== void 0)) throw new TypeError("Ambiguous action proposal settlement");
|
|
3960
|
+
const status = leaseStatus(row2, command, now);
|
|
3961
|
+
if (status !== "valid") return result(status, row2);
|
|
3962
|
+
const next = snapshotActionProposal(row2);
|
|
3963
|
+
next.execution = command.status === "succeeded" ? {
|
|
3964
|
+
status: "succeeded",
|
|
3965
|
+
generation: command.generation,
|
|
3966
|
+
lease: null,
|
|
3967
|
+
...command.result === void 0 ? {} : {
|
|
3968
|
+
result: command.result
|
|
3969
|
+
}
|
|
3970
|
+
} : {
|
|
3971
|
+
status: "failed",
|
|
3972
|
+
generation: command.generation,
|
|
3973
|
+
lease: null,
|
|
3974
|
+
error: command.error
|
|
3975
|
+
};
|
|
3976
|
+
if (command.ui !== void 0) canonicalActionProposalJson(command.ui);
|
|
3977
|
+
if (command.text !== void 0 && typeof command.text !== "string") throw new TypeError("Outcome text must be a string");
|
|
3978
|
+
next.updatedAt = now;
|
|
3979
|
+
return result("applied", attachActionProposalOutcome(next, now, command.ui, command.text));
|
|
3980
|
+
}
|
|
3981
|
+
__name(transitionActionProposalSettlement, "transitionActionProposalSettlement");
|
|
3982
|
+
function transitionActionProposalSupersession(row2, replacement, command, now) {
|
|
3983
|
+
checkTime(now);
|
|
3984
|
+
checkString(command.replacementProposalId);
|
|
3985
|
+
checkString(command.actorRef);
|
|
3986
|
+
checkString(command.via);
|
|
3987
|
+
if (replacement.id !== command.replacementProposalId || row2.id === replacement.id || !actionProposalScopeMatches(row2, replacement) || row2.toolName !== replacement.toolName || !row2.replacementKey || row2.replacementKey !== replacement.replacementKey) return result("conflict", row2);
|
|
3988
|
+
if (row2.decision === "superseded") return result(row2.supersededBy === replacement.id ? "unchanged" : "conflict", row2);
|
|
3989
|
+
if (row2.decision !== "pending") return result("conflict", row2);
|
|
3990
|
+
if (row2.expiresAt !== null && now >= row2.expiresAt) return {
|
|
3991
|
+
...transitionActionProposalDecision(row2, {
|
|
3992
|
+
decision: "expired",
|
|
3993
|
+
actorRef: "system",
|
|
3994
|
+
via: "expiry"
|
|
3995
|
+
}, now),
|
|
3996
|
+
status: "expired"
|
|
3997
|
+
};
|
|
3998
|
+
const next = snapshotActionProposal({
|
|
3999
|
+
...row2,
|
|
4000
|
+
decision: "superseded",
|
|
4001
|
+
supersededBy: replacement.id,
|
|
4002
|
+
decisionAudit: {
|
|
4003
|
+
actorRef: command.actorRef,
|
|
4004
|
+
via: command.via,
|
|
4005
|
+
replacementProposalId: replacement.id,
|
|
4006
|
+
at: now
|
|
4007
|
+
},
|
|
4008
|
+
updatedAt: now
|
|
4009
|
+
});
|
|
4010
|
+
return result("applied", attachActionProposalOutcome(next, now));
|
|
4011
|
+
}
|
|
4012
|
+
__name(transitionActionProposalSupersession, "transitionActionProposalSupersession");
|
|
4013
|
+
|
|
4014
|
+
// src/genui/builtins.ts
|
|
4015
|
+
var str = /* @__PURE__ */ __name((description, extra = {}) => ({
|
|
4016
|
+
type: "string",
|
|
4017
|
+
...description !== void 0 ? {
|
|
4018
|
+
description
|
|
4019
|
+
} : {},
|
|
4020
|
+
...extra
|
|
4021
|
+
}), "str");
|
|
4022
|
+
var obj = /* @__PURE__ */ __name((properties, required = []) => ({
|
|
4023
|
+
type: "object",
|
|
4024
|
+
properties,
|
|
4025
|
+
required,
|
|
4026
|
+
additionalProperties: false
|
|
4027
|
+
}), "obj");
|
|
4028
|
+
var arr = /* @__PURE__ */ __name((items, extra = {}) => ({
|
|
4029
|
+
type: "array",
|
|
4030
|
+
items,
|
|
4031
|
+
...extra
|
|
4032
|
+
}), "arr");
|
|
4033
|
+
var cell = {
|
|
4034
|
+
type: [
|
|
4035
|
+
"string",
|
|
4036
|
+
"number",
|
|
4037
|
+
"boolean",
|
|
4038
|
+
"null"
|
|
4039
|
+
]
|
|
4040
|
+
};
|
|
4041
|
+
var row = {
|
|
4042
|
+
type: "object",
|
|
4043
|
+
additionalProperties: cell
|
|
4044
|
+
};
|
|
4045
|
+
var s = /* @__PURE__ */ __name((value) => value === null || value === void 0 ? "" : String(value), "s");
|
|
4046
|
+
var heading = /* @__PURE__ */ __name((props) => props.title ? `*${s(props.title)}*
|
|
4047
|
+
` : "", "heading");
|
|
4048
|
+
function textTable(columns, rows, max = 15) {
|
|
4049
|
+
const shown = rows.slice(0, max);
|
|
4050
|
+
const widths = columns.map((column) => Math.min(28, Math.max(column.label.length, ...shown.map((r) => s(r[column.key]).length))));
|
|
4051
|
+
const format = /* @__PURE__ */ __name((values) => values.map((value, index) => value.slice(0, widths[index]).padEnd(widths[index] ?? 0)).join(" "), "format");
|
|
4052
|
+
const lines = [
|
|
4053
|
+
format(columns.map((column) => column.label)),
|
|
4054
|
+
widths.map((width) => "-".repeat(width)).join(" "),
|
|
4055
|
+
...shown.map((r) => format(columns.map((column) => s(r[column.key]))))
|
|
4056
|
+
];
|
|
4057
|
+
if (rows.length > max) lines.push(`\u2026 ${rows.length - max} more rows`);
|
|
4058
|
+
return `\`\`\`
|
|
4059
|
+
${lines.join("\n")}
|
|
4060
|
+
\`\`\``;
|
|
4061
|
+
}
|
|
4062
|
+
__name(textTable, "textTable");
|
|
4063
|
+
function lineDiff(before, after) {
|
|
4064
|
+
const a = before.split("\n");
|
|
4065
|
+
const b = after.split("\n");
|
|
4066
|
+
if (a.length * b.length > 25e4) {
|
|
4067
|
+
return [
|
|
4068
|
+
...a.map((text) => ({
|
|
4069
|
+
op: "del",
|
|
4070
|
+
text
|
|
4071
|
+
})),
|
|
4072
|
+
...b.map((text) => ({
|
|
4073
|
+
op: "add",
|
|
4074
|
+
text
|
|
4075
|
+
}))
|
|
4076
|
+
];
|
|
4077
|
+
}
|
|
4078
|
+
const dp = Array.from({
|
|
4079
|
+
length: a.length + 1
|
|
4080
|
+
}, () => new Array(b.length + 1).fill(0));
|
|
4081
|
+
const at = /* @__PURE__ */ __name((i2, j2) => dp[i2]?.[j2] ?? 0, "at");
|
|
4082
|
+
for (let i2 = a.length - 1; i2 >= 0; i2--) {
|
|
4083
|
+
for (let j2 = b.length - 1; j2 >= 0; j2--) {
|
|
4084
|
+
dp[i2][j2] = a[i2] === b[j2] ? at(i2 + 1, j2 + 1) + 1 : Math.max(at(i2 + 1, j2), at(i2, j2 + 1));
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
const out = [];
|
|
4088
|
+
let i = 0;
|
|
4089
|
+
let j = 0;
|
|
4090
|
+
while (i < a.length && j < b.length) {
|
|
4091
|
+
if (a[i] === b[j]) {
|
|
4092
|
+
out.push({
|
|
4093
|
+
op: "same",
|
|
4094
|
+
text: a[i]
|
|
4095
|
+
});
|
|
4096
|
+
i++;
|
|
4097
|
+
j++;
|
|
4098
|
+
} else if (at(i + 1, j) >= at(i, j + 1)) {
|
|
4099
|
+
out.push({
|
|
4100
|
+
op: "del",
|
|
4101
|
+
text: a[i++]
|
|
4102
|
+
});
|
|
4103
|
+
} else {
|
|
4104
|
+
out.push({
|
|
4105
|
+
op: "add",
|
|
4106
|
+
text: b[j++]
|
|
4107
|
+
});
|
|
4108
|
+
}
|
|
4109
|
+
}
|
|
4110
|
+
while (i < a.length) out.push({
|
|
4111
|
+
op: "del",
|
|
4112
|
+
text: a[i++]
|
|
4113
|
+
});
|
|
4114
|
+
while (j < b.length) out.push({
|
|
4115
|
+
op: "add",
|
|
4116
|
+
text: b[j++]
|
|
4117
|
+
});
|
|
4118
|
+
return out;
|
|
4119
|
+
}
|
|
4120
|
+
__name(lineDiff, "lineDiff");
|
|
4121
|
+
function bar(value, max, width = 20) {
|
|
4122
|
+
const n = max > 0 ? Math.round(Math.abs(value) / max * width) : 0;
|
|
4123
|
+
return "\u2588".repeat(n) || "\u258F";
|
|
4124
|
+
}
|
|
4125
|
+
__name(bar, "bar");
|
|
4126
|
+
var DataTable = defineComponent({
|
|
4127
|
+
name: "DataTable",
|
|
4128
|
+
title: "Data table",
|
|
4129
|
+
description: "Tabular data (records with the same fields) as a sortable table. Prefer it over markdown tables for more than 3 rows.",
|
|
4130
|
+
props: obj({
|
|
4131
|
+
title: str("Short caption"),
|
|
4132
|
+
columns: arr(obj({
|
|
4133
|
+
key: str("Field name in each row"),
|
|
4134
|
+
label: str("Column header"),
|
|
4135
|
+
align: str(void 0, {
|
|
4136
|
+
enum: [
|
|
4137
|
+
"left",
|
|
4138
|
+
"right",
|
|
4139
|
+
"center"
|
|
4140
|
+
]
|
|
4141
|
+
}),
|
|
4142
|
+
format: str("How to format values", {
|
|
4143
|
+
enum: [
|
|
4144
|
+
"text",
|
|
4145
|
+
"number",
|
|
4146
|
+
"currency",
|
|
4147
|
+
"percent",
|
|
4148
|
+
"date",
|
|
4149
|
+
"link"
|
|
4150
|
+
]
|
|
4151
|
+
})
|
|
4152
|
+
}, [
|
|
4153
|
+
"key",
|
|
4154
|
+
"label"
|
|
4155
|
+
]), {
|
|
4156
|
+
minItems: 1,
|
|
4157
|
+
maxItems: 12
|
|
4158
|
+
}),
|
|
4159
|
+
rows: arr(row, {
|
|
4160
|
+
maxItems: 500
|
|
4161
|
+
})
|
|
4162
|
+
}, [
|
|
4163
|
+
"columns",
|
|
4164
|
+
"rows"
|
|
4165
|
+
]),
|
|
4166
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${textTable(props.columns ?? [], props.rows ?? [])}`, "fallbackText")
|
|
4167
|
+
});
|
|
4168
|
+
var Chart = defineComponent({
|
|
4169
|
+
name: "Chart",
|
|
4170
|
+
title: "Chart",
|
|
4171
|
+
description: "`bar` to compare categories, `line` for a trend over time. `data` is a list of points; `xKey` names the category/time field and each series names a numeric field.",
|
|
4172
|
+
props: obj({
|
|
4173
|
+
type: str("Chart type", {
|
|
4174
|
+
enum: [
|
|
4175
|
+
"bar",
|
|
4176
|
+
"line"
|
|
4177
|
+
]
|
|
4178
|
+
}),
|
|
4179
|
+
title: str(),
|
|
4180
|
+
xKey: str("Field of each point used for the x axis"),
|
|
4181
|
+
series: arr(obj({
|
|
4182
|
+
key: str("Numeric field"),
|
|
4183
|
+
label: str()
|
|
4184
|
+
}, [
|
|
4185
|
+
"key"
|
|
4186
|
+
]), {
|
|
4187
|
+
minItems: 1,
|
|
4188
|
+
maxItems: 6
|
|
4189
|
+
}),
|
|
4190
|
+
data: arr(row, {
|
|
4191
|
+
minItems: 1,
|
|
4192
|
+
maxItems: 200
|
|
4193
|
+
}),
|
|
4194
|
+
unit: str("Unit shown after values, e.g. `KB` or `%`")
|
|
4195
|
+
}, [
|
|
4196
|
+
"type",
|
|
4197
|
+
"xKey",
|
|
4198
|
+
"series",
|
|
4199
|
+
"data"
|
|
4200
|
+
]),
|
|
4201
|
+
fallbackText: /* @__PURE__ */ __name((props) => {
|
|
4202
|
+
const series = props.series ?? [];
|
|
4203
|
+
const data = props.data ?? [];
|
|
4204
|
+
const first = series[0]?.key ?? "";
|
|
4205
|
+
const max = Math.max(0, ...data.map((point) => Math.abs(Number(point[first]) || 0)));
|
|
4206
|
+
const unit = props.unit ? ` ${s(props.unit)}` : "";
|
|
4207
|
+
const lines = data.slice(0, 20).map((point) => `${s(point[props.xKey]).slice(0, 18).padEnd(18)} ${bar(Number(point[first]) || 0, max)} ${s(point[first])}${unit}`);
|
|
4208
|
+
return `${heading(props)}\`\`\`
|
|
4209
|
+
${lines.join("\n")}
|
|
4210
|
+
\`\`\``;
|
|
4211
|
+
}, "fallbackText")
|
|
4212
|
+
});
|
|
4213
|
+
var KpiCards = defineComponent({
|
|
4214
|
+
name: "KpiCards",
|
|
4215
|
+
title: "KPI cards",
|
|
4216
|
+
description: "A few key numbers (metrics, totals, counts) as cards.",
|
|
4217
|
+
props: obj({
|
|
4218
|
+
title: str(),
|
|
4219
|
+
items: arr(obj({
|
|
4220
|
+
label: str(),
|
|
4221
|
+
value: {
|
|
4222
|
+
type: [
|
|
4223
|
+
"string",
|
|
4224
|
+
"number"
|
|
4225
|
+
]
|
|
4226
|
+
},
|
|
4227
|
+
delta: str("Change, e.g. `+12%`"),
|
|
4228
|
+
trend: str(void 0, {
|
|
4229
|
+
enum: [
|
|
4230
|
+
"up",
|
|
4231
|
+
"down",
|
|
4232
|
+
"flat"
|
|
4233
|
+
]
|
|
4234
|
+
}),
|
|
4235
|
+
hint: str()
|
|
4236
|
+
}, [
|
|
4237
|
+
"label",
|
|
4238
|
+
"value"
|
|
4239
|
+
]), {
|
|
4240
|
+
minItems: 1,
|
|
4241
|
+
maxItems: 8
|
|
4242
|
+
})
|
|
4243
|
+
}, [
|
|
4244
|
+
"items"
|
|
4245
|
+
]),
|
|
4246
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.items ?? []).map((item) => `\u2022 *${s(item.label)}:* ${s(item.value)}${item.delta ? ` (${s(item.delta)})` : ""}`).join("\n")}`, "fallbackText")
|
|
4247
|
+
});
|
|
4248
|
+
var SourceCards = defineComponent({
|
|
4249
|
+
name: "SourceCards",
|
|
4250
|
+
title: "Sources",
|
|
4251
|
+
description: "The documents, pages or links an answer is based on, as cards.",
|
|
4252
|
+
props: obj({
|
|
4253
|
+
title: str(),
|
|
4254
|
+
items: arr(obj({
|
|
4255
|
+
title: str(),
|
|
4256
|
+
url: str(),
|
|
4257
|
+
snippet: str(),
|
|
4258
|
+
source: str("e.g. Wiki, GitHub")
|
|
4259
|
+
}, [
|
|
4260
|
+
"title"
|
|
4261
|
+
]), {
|
|
4262
|
+
minItems: 1,
|
|
4263
|
+
maxItems: 12
|
|
4264
|
+
})
|
|
4265
|
+
}, [
|
|
4266
|
+
"items"
|
|
4267
|
+
]),
|
|
4268
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.items ?? []).map((item) => `\u2022 ${item.url ? `<${s(item.url)}|${s(item.title)}>` : s(item.title)}${item.source ? ` \u2014 ${s(item.source)}` : ""}`).join("\n")}`, "fallbackText")
|
|
4269
|
+
});
|
|
4270
|
+
var Checklist = defineComponent({
|
|
4271
|
+
name: "Checklist",
|
|
4272
|
+
title: "Checklist",
|
|
4273
|
+
description: "Steps or a to-do list with done/not-done state.",
|
|
4274
|
+
props: obj({
|
|
4275
|
+
title: str(),
|
|
4276
|
+
items: arr(obj({
|
|
4277
|
+
label: str(),
|
|
4278
|
+
done: {
|
|
4279
|
+
type: "boolean"
|
|
4280
|
+
},
|
|
4281
|
+
note: str()
|
|
4282
|
+
}, [
|
|
4283
|
+
"label"
|
|
4284
|
+
]), {
|
|
4285
|
+
minItems: 1,
|
|
4286
|
+
maxItems: 50
|
|
4287
|
+
})
|
|
4288
|
+
}, [
|
|
4289
|
+
"items"
|
|
4290
|
+
]),
|
|
4291
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.items ?? []).map((item) => `${item.done ? "\u2611" : "\u2610"} ${s(item.label)}${item.note ? ` \u2014 _${s(item.note)}_` : ""}`).join("\n")}`, "fallbackText")
|
|
4292
|
+
});
|
|
4293
|
+
var Timeline = defineComponent({
|
|
4294
|
+
name: "Timeline",
|
|
4295
|
+
title: "Timeline",
|
|
4296
|
+
description: "Events in chronological order (the history of a project, an incident, a deal).",
|
|
4297
|
+
props: obj({
|
|
4298
|
+
title: str(),
|
|
4299
|
+
events: arr(obj({
|
|
4300
|
+
date: str(),
|
|
4301
|
+
title: str(),
|
|
4302
|
+
description: str()
|
|
4303
|
+
}, [
|
|
4304
|
+
"title"
|
|
4305
|
+
]), {
|
|
4306
|
+
minItems: 1,
|
|
4307
|
+
maxItems: 50
|
|
4308
|
+
})
|
|
4309
|
+
}, [
|
|
4310
|
+
"events"
|
|
4311
|
+
]),
|
|
4312
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}${(props.events ?? []).map((event) => `\u2022 ${event.date ? `*${s(event.date)}* ` : ""}${s(event.title)}${event.description ? ` \u2014 ${s(event.description)}` : ""}`).join("\n")}`, "fallbackText")
|
|
4313
|
+
});
|
|
4314
|
+
var CodeBlock = defineComponent({
|
|
4315
|
+
name: "CodeBlock",
|
|
4316
|
+
title: "Code",
|
|
4317
|
+
description: "A code snippet or file excerpt with syntax highlighting.",
|
|
4318
|
+
props: obj({
|
|
4319
|
+
title: str(),
|
|
4320
|
+
language: str(),
|
|
4321
|
+
code: str()
|
|
4322
|
+
}, [
|
|
4323
|
+
"code"
|
|
4324
|
+
]),
|
|
4325
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}\`\`\`
|
|
4326
|
+
${s(props.code)}
|
|
4327
|
+
\`\`\``, "fallbackText")
|
|
4328
|
+
});
|
|
4329
|
+
var Diff = defineComponent({
|
|
4330
|
+
name: "Diff",
|
|
4331
|
+
title: "Diff",
|
|
4332
|
+
description: "A before/after change to a text or code file, as a line diff.",
|
|
4333
|
+
props: obj({
|
|
4334
|
+
title: str(),
|
|
4335
|
+
language: str(),
|
|
4336
|
+
before: str(),
|
|
4337
|
+
after: str()
|
|
4338
|
+
}, [
|
|
4339
|
+
"before",
|
|
4340
|
+
"after"
|
|
4341
|
+
]),
|
|
4342
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${heading(props)}\`\`\`
|
|
4343
|
+
${lineDiff(s(props.before), s(props.after)).map((line) => `${line.op === "add" ? "+" : line.op === "del" ? "-" : " "} ${line.text}`).join("\n")}
|
|
4344
|
+
\`\`\``, "fallbackText")
|
|
4345
|
+
});
|
|
4346
|
+
var Callout = defineComponent({
|
|
4347
|
+
name: "Callout",
|
|
4348
|
+
title: "Callout",
|
|
4349
|
+
description: "A short note, warning or success message, emphasized.",
|
|
4350
|
+
props: obj({
|
|
4351
|
+
tone: str(void 0, {
|
|
4352
|
+
enum: [
|
|
4353
|
+
"info",
|
|
4354
|
+
"success",
|
|
4355
|
+
"warning",
|
|
4356
|
+
"danger"
|
|
4357
|
+
]
|
|
4358
|
+
}),
|
|
4359
|
+
title: str(),
|
|
4360
|
+
text: str()
|
|
4361
|
+
}, [
|
|
4362
|
+
"text"
|
|
4363
|
+
]),
|
|
4364
|
+
fallbackText: /* @__PURE__ */ __name((props) => `${props.tone === "warning" || props.tone === "danger" ? ":warning: " : ":information_source: "}${heading(props)}${s(props.text)}`, "fallbackText")
|
|
4365
|
+
});
|
|
4366
|
+
var Stack = defineComponent({
|
|
4367
|
+
name: "Stack",
|
|
4368
|
+
title: "Stack",
|
|
4369
|
+
description: "Lays its children out vertically (or horizontally with direction=row).",
|
|
4370
|
+
props: obj({
|
|
4371
|
+
direction: str(void 0, {
|
|
4372
|
+
enum: [
|
|
4373
|
+
"column",
|
|
4374
|
+
"row"
|
|
4375
|
+
]
|
|
4376
|
+
}),
|
|
4377
|
+
gap: {
|
|
4378
|
+
type: "number"
|
|
4379
|
+
}
|
|
4380
|
+
}),
|
|
4381
|
+
children: true,
|
|
4382
|
+
fallbackText: /* @__PURE__ */ __name(() => "", "fallbackText")
|
|
4383
|
+
});
|
|
4384
|
+
var Card = defineComponent({
|
|
4385
|
+
name: "Card",
|
|
4386
|
+
title: "Card",
|
|
4387
|
+
description: "A box with an optional title around its children.",
|
|
4388
|
+
props: obj({
|
|
4389
|
+
title: str(),
|
|
4390
|
+
subtitle: str()
|
|
4391
|
+
}),
|
|
4392
|
+
children: true,
|
|
4393
|
+
fallbackText: /* @__PURE__ */ __name((props) => props.title ? `*${s(props.title)}*${props.subtitle ? ` \u2014 ${s(props.subtitle)}` : ""}` : "", "fallbackText")
|
|
4394
|
+
});
|
|
4395
|
+
var Heading = defineComponent({
|
|
4396
|
+
name: "Heading",
|
|
4397
|
+
title: "Heading",
|
|
4398
|
+
description: "A heading.",
|
|
4399
|
+
props: obj({
|
|
4400
|
+
text: str()
|
|
4401
|
+
}, [
|
|
4402
|
+
"text"
|
|
4403
|
+
]),
|
|
4404
|
+
fallbackText: /* @__PURE__ */ __name((props) => `*${s(props.text)}*`, "fallbackText")
|
|
4405
|
+
});
|
|
4406
|
+
var Text = defineComponent({
|
|
4407
|
+
name: "Text",
|
|
4408
|
+
title: "Text",
|
|
4409
|
+
description: "A paragraph of plain text (no markdown).",
|
|
4410
|
+
props: obj({
|
|
4411
|
+
text: str(),
|
|
4412
|
+
muted: {
|
|
4413
|
+
type: "boolean"
|
|
4414
|
+
}
|
|
4415
|
+
}, [
|
|
4416
|
+
"text"
|
|
4417
|
+
]),
|
|
4418
|
+
fallbackText: /* @__PURE__ */ __name((props) => s(props.text), "fallbackText")
|
|
4419
|
+
});
|
|
4420
|
+
var Badge = defineComponent({
|
|
4421
|
+
name: "Badge",
|
|
4422
|
+
title: "Badge",
|
|
4423
|
+
description: "A small label.",
|
|
4424
|
+
props: obj({
|
|
4425
|
+
text: str(),
|
|
4426
|
+
tone: str(void 0, {
|
|
4427
|
+
enum: [
|
|
4428
|
+
"neutral",
|
|
4429
|
+
"brand",
|
|
4430
|
+
"success",
|
|
4431
|
+
"warning",
|
|
4432
|
+
"danger"
|
|
4433
|
+
]
|
|
4434
|
+
})
|
|
4435
|
+
}, [
|
|
4436
|
+
"text"
|
|
4437
|
+
]),
|
|
4438
|
+
fallbackText: /* @__PURE__ */ __name((props) => `[${s(props.text)}]`, "fallbackText")
|
|
4439
|
+
});
|
|
4440
|
+
var Link = defineComponent({
|
|
4441
|
+
name: "Link",
|
|
4442
|
+
title: "Link",
|
|
4443
|
+
description: "A link to an http(s) URL.",
|
|
4444
|
+
props: obj({
|
|
4445
|
+
text: str(),
|
|
4446
|
+
url: str(void 0, {
|
|
4447
|
+
pattern: "^https?://"
|
|
4448
|
+
})
|
|
4449
|
+
}, [
|
|
4450
|
+
"text",
|
|
4451
|
+
"url"
|
|
4452
|
+
]),
|
|
4453
|
+
fallbackText: /* @__PURE__ */ __name((props) => `<${s(props.url)}|${s(props.text || props.url)}>`, "fallbackText")
|
|
4454
|
+
});
|
|
4455
|
+
var Image = defineComponent({
|
|
4456
|
+
name: "Image",
|
|
4457
|
+
title: "Image",
|
|
4458
|
+
description: "An image from an https URL.",
|
|
4459
|
+
props: obj({
|
|
4460
|
+
url: str(void 0, {
|
|
4461
|
+
pattern: "^https://"
|
|
4462
|
+
}),
|
|
4463
|
+
alt: str()
|
|
4464
|
+
}, [
|
|
4465
|
+
"url"
|
|
4466
|
+
]),
|
|
4467
|
+
fallbackText: /* @__PURE__ */ __name((props) => s(props.url), "fallbackText")
|
|
4468
|
+
});
|
|
4469
|
+
|
|
4470
|
+
// src/genui/registry.ts
|
|
4471
|
+
function snapshotComponentPresentation(value) {
|
|
4472
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4473
|
+
const check2 = /* @__PURE__ */ __name((entry) => {
|
|
4474
|
+
if (entry === null || typeof entry === "string" || typeof entry === "boolean") return;
|
|
4475
|
+
if (typeof entry === "number" && Number.isFinite(entry)) return;
|
|
4476
|
+
if (typeof entry !== "object" || entry === null) throw new TypeError("genui: presentation must contain only JSON values");
|
|
4477
|
+
if (seen.has(entry)) throw new TypeError("genui: presentation must contain acyclic JSON values");
|
|
4478
|
+
if (!Array.isArray(entry) && Object.getPrototypeOf(entry) !== Object.prototype && Object.getPrototypeOf(entry) !== null) throw new TypeError("genui: presentation must contain plain JSON objects");
|
|
4479
|
+
seen.add(entry);
|
|
4480
|
+
for (const item of Object.values(entry)) check2(item);
|
|
4481
|
+
seen.delete(entry);
|
|
4482
|
+
}, "check");
|
|
4483
|
+
check2(value);
|
|
4484
|
+
return JSON.parse(JSON.stringify(value));
|
|
4485
|
+
}
|
|
4486
|
+
__name(snapshotComponentPresentation, "snapshotComponentPresentation");
|
|
4487
|
+
function createComponent(definition, options = {}) {
|
|
4488
|
+
defineComponent(definition);
|
|
4489
|
+
const catalog = defineCatalog([
|
|
4490
|
+
definition
|
|
4491
|
+
], options);
|
|
4492
|
+
const factory = /* @__PURE__ */ __name(async (props) => {
|
|
4493
|
+
const result2 = await validateProps(definition.props, props, catalog.validator);
|
|
4494
|
+
if (!result2.ok) throw new Error(`genui: invalid ${definition.name} props: ${formatIssues(result2.issues)}`);
|
|
4495
|
+
const normalized = snapshotComponentPresentation(result2.value);
|
|
4496
|
+
if (typeof normalized !== "object" || normalized === null || Array.isArray(normalized)) throw new TypeError("genui: component props must be a JSON object");
|
|
4497
|
+
const portable = await catalog.validate(definition.name, normalized);
|
|
4498
|
+
if (!portable.ok || canonicalJson(snapshotComponentPresentation(portable.value)) !== canonicalJson(normalized)) {
|
|
4499
|
+
throw new Error(`genui: ${definition.name} requires outputProps accepting stable normalized JSON props`);
|
|
4500
|
+
}
|
|
4501
|
+
return {
|
|
4502
|
+
component: definition.name,
|
|
4503
|
+
props: normalized,
|
|
4504
|
+
version: definition.version ?? 1,
|
|
4505
|
+
fallbackText: componentToText(catalog, definition.name, normalized)
|
|
4506
|
+
};
|
|
4507
|
+
}, "factory");
|
|
4508
|
+
return Object.assign(factory, {
|
|
4509
|
+
definition
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4512
|
+
__name(createComponent, "createComponent");
|
|
4513
|
+
var table = createComponent(DataTable);
|
|
4514
|
+
var chart = createComponent(Chart);
|
|
4515
|
+
function validatePresentationBatch(presentations) {
|
|
4516
|
+
const batch = Array.isArray(presentations) ? presentations : [
|
|
4517
|
+
presentations
|
|
4518
|
+
];
|
|
4519
|
+
return batch.map((item) => {
|
|
4520
|
+
const presentation = snapshotComponentPresentation(item);
|
|
4521
|
+
if (typeof presentation !== "object" || presentation === null || typeof presentation.component !== "string" || !/^[A-Za-z][A-Za-z0-9]{0,63}$/.test(presentation.component) || !Number.isSafeInteger(presentation.version) || presentation.version <= 0 || typeof presentation.fallbackText !== "string" || typeof presentation.props !== "object" || presentation.props === null || Array.isArray(presentation.props)) {
|
|
4522
|
+
throw new TypeError("genui: invalid component presentation");
|
|
4523
|
+
}
|
|
4524
|
+
return presentation;
|
|
4525
|
+
});
|
|
4526
|
+
}
|
|
4527
|
+
__name(validatePresentationBatch, "validatePresentationBatch");
|
|
4528
|
+
function canonicalJson(value) {
|
|
4529
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
4530
|
+
if (typeof value === "object" && value !== null) {
|
|
4531
|
+
const record2 = value;
|
|
4532
|
+
return `{${Object.keys(record2).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record2[key])}`).join(",")}}`;
|
|
4533
|
+
}
|
|
4534
|
+
return JSON.stringify(value);
|
|
4535
|
+
}
|
|
4536
|
+
__name(canonicalJson, "canonicalJson");
|
|
4537
|
+
|
|
4538
|
+
// src/tool-presentations.ts
|
|
4539
|
+
async function emitToolPresentations(handler, output, ctx, toolName) {
|
|
4540
|
+
if (handler.present === void 0) return;
|
|
4541
|
+
try {
|
|
4542
|
+
const result2 = await handler.present(output, ctx);
|
|
4543
|
+
if (result2 === void 0) return;
|
|
4544
|
+
const batch = validatePresentationBatch(result2);
|
|
4545
|
+
for (const presentation of batch) {
|
|
4546
|
+
await ctx.emitUi(presentation.component, presentation.props, {
|
|
4547
|
+
version: presentation.version,
|
|
4548
|
+
fallbackText: presentation.fallbackText
|
|
4549
|
+
});
|
|
4550
|
+
}
|
|
4551
|
+
} catch (error) {
|
|
4552
|
+
if (ctx.onPresentationError !== void 0) {
|
|
4553
|
+
try {
|
|
4554
|
+
await ctx.onPresentationError(error, {
|
|
4555
|
+
toolName
|
|
4556
|
+
});
|
|
4557
|
+
return;
|
|
4558
|
+
} catch (reportError) {
|
|
4559
|
+
console.warn(`Tool "${toolName}" presentation error reporter failed`, reportError);
|
|
4560
|
+
}
|
|
4561
|
+
} else {
|
|
4562
|
+
console.warn(`Tool "${toolName}" presentation failed after successful execution`, error);
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
__name(emitToolPresentations, "emitToolPresentations");
|
|
4567
|
+
|
|
2829
4568
|
// src/tool-registry.ts
|
|
2830
4569
|
var ToolForbiddenError = class extends Error {
|
|
2831
4570
|
static {
|
|
@@ -2868,6 +4607,35 @@ var ToolInputInvalidError = class extends Error {
|
|
|
2868
4607
|
this.name = "ToolInputInvalidError";
|
|
2869
4608
|
}
|
|
2870
4609
|
};
|
|
4610
|
+
var ToolPreflightDeniedError = class extends Error {
|
|
4611
|
+
static {
|
|
4612
|
+
__name(this, "ToolPreflightDeniedError");
|
|
4613
|
+
}
|
|
4614
|
+
toolName;
|
|
4615
|
+
reason;
|
|
4616
|
+
constructor(toolName, reason) {
|
|
4617
|
+
super(reason), this.toolName = toolName, this.reason = reason;
|
|
4618
|
+
this.name = "ToolPreflightDeniedError";
|
|
4619
|
+
}
|
|
4620
|
+
};
|
|
4621
|
+
var ToolInputDriftError = class extends Error {
|
|
4622
|
+
static {
|
|
4623
|
+
__name(this, "ToolInputDriftError");
|
|
4624
|
+
}
|
|
4625
|
+
toolName;
|
|
4626
|
+
constructor(toolName) {
|
|
4627
|
+
super(`Tool "${toolName}" input differs from its trusted snapshot`), this.toolName = toolName;
|
|
4628
|
+
this.name = "ToolInputDriftError";
|
|
4629
|
+
}
|
|
4630
|
+
};
|
|
4631
|
+
function assertTrustedInput(name, value, approved) {
|
|
4632
|
+
try {
|
|
4633
|
+
if (canonicalActionProposalJson(value) === canonicalActionProposalJson(approved)) return;
|
|
4634
|
+
} catch {
|
|
4635
|
+
}
|
|
4636
|
+
throw new ToolInputDriftError(name);
|
|
4637
|
+
}
|
|
4638
|
+
__name(assertTrustedInput, "assertTrustedInput");
|
|
2871
4639
|
var ToolRegistry = class {
|
|
2872
4640
|
static {
|
|
2873
4641
|
__name(this, "ToolRegistry");
|
|
@@ -2879,6 +4647,15 @@ var ToolRegistry = class {
|
|
|
2879
4647
|
handler
|
|
2880
4648
|
});
|
|
2881
4649
|
}
|
|
4650
|
+
/** Whether a successful preflight shortcut has UI to journal. */
|
|
4651
|
+
hasPresentation(name) {
|
|
4652
|
+
return typeof this.entries.get(name)?.handler.present === "function";
|
|
4653
|
+
}
|
|
4654
|
+
/** Present an already authorized successful domain result without executing its action again. */
|
|
4655
|
+
async presentOutput(name, output, ctx) {
|
|
4656
|
+
const entry = this.entries.get(name);
|
|
4657
|
+
if (entry !== void 0) await emitToolPresentations(entry.handler, output, ctx, name);
|
|
4658
|
+
}
|
|
2882
4659
|
has(name) {
|
|
2883
4660
|
return this.entries.has(name);
|
|
2884
4661
|
}
|
|
@@ -2915,11 +4692,12 @@ var ToolRegistry = class {
|
|
|
2915
4692
|
*/
|
|
2916
4693
|
async definitionsFor(actor, policy, allowedTools, scope = {}) {
|
|
2917
4694
|
const visible = await this.visibleEntries(actor, policy, allowedTools);
|
|
2918
|
-
|
|
4695
|
+
const definitions = await Promise.all(visible.map(async ({ spec, handler }) => {
|
|
2919
4696
|
const override = handler.describe === void 0 ? void 0 : await handler.describe({
|
|
2920
4697
|
actor,
|
|
2921
4698
|
...scope
|
|
2922
4699
|
});
|
|
4700
|
+
if (override?.available === false) return null;
|
|
2923
4701
|
return {
|
|
2924
4702
|
name: spec.name,
|
|
2925
4703
|
kind: spec.kind,
|
|
@@ -2927,6 +4705,7 @@ var ToolRegistry = class {
|
|
|
2927
4705
|
inputSchema: override?.inputSchema ?? spec.inputSchema
|
|
2928
4706
|
};
|
|
2929
4707
|
}));
|
|
4708
|
+
return definitions.filter((definition) => definition !== null);
|
|
2930
4709
|
}
|
|
2931
4710
|
/**
|
|
2932
4711
|
* The specs {@link definitionsFor} offers the model, whole — the same four gates (allow-list,
|
|
@@ -2952,6 +4731,41 @@ var ToolRegistry = class {
|
|
|
2952
4731
|
* moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.
|
|
2953
4732
|
*/
|
|
2954
4733
|
async invoke(name, input, ctx, policy, options = {}) {
|
|
4734
|
+
const { entry, value, ctx: withEmit } = await this.validated(name, input, ctx, policy, options);
|
|
4735
|
+
const trusted = Object.hasOwn(options, "approvedInput");
|
|
4736
|
+
if (trusted) assertTrustedInput(name, value, options.approvedInput);
|
|
4737
|
+
const executionInput = trusted ? snapshotActionProposal(value) : value;
|
|
4738
|
+
const hookInput = trusted ? snapshotActionProposal(executionInput) : value;
|
|
4739
|
+
const result2 = entry.spec.kind === "action" ? await entry.handler.preflight?.(hookInput, withEmit, {
|
|
4740
|
+
phase: "execute"
|
|
4741
|
+
}) : void 0;
|
|
4742
|
+
if (trusted) assertTrustedInput(name, hookInput, executionInput);
|
|
4743
|
+
if (result2?.status === "denied") throw new ToolPreflightDeniedError(name, result2.reason);
|
|
4744
|
+
const output = result2?.status === "completed" ? result2.output : await entry.handler.execute(executionInput, withEmit);
|
|
4745
|
+
await emitToolPresentations(entry.handler, output, withEmit, name);
|
|
4746
|
+
return output;
|
|
4747
|
+
}
|
|
4748
|
+
/** Authorize and validate without executing. The caller journals this result before approval. */
|
|
4749
|
+
async prepare(name, input, ctx, policy, options = {}) {
|
|
4750
|
+
return (await this.prepareValidated(name, input, ctx, policy, options)).preflight;
|
|
4751
|
+
}
|
|
4752
|
+
/** Expose the single schema parse; snapshotInput opts proposal callers into immutable JSON. */
|
|
4753
|
+
async prepareValidated(name, input, ctx, policy, options = {}) {
|
|
4754
|
+
const { entry, value, ctx: withEmit } = await this.validated(name, input, ctx, policy, options);
|
|
4755
|
+
const normalized = options.snapshotInput === true ? snapshotActionProposal(value) : value;
|
|
4756
|
+
const hookInput = options.snapshotInput === true ? snapshotActionProposal(normalized) : value;
|
|
4757
|
+
const preflight = (entry.spec.kind === "action" ? await entry.handler.preflight?.(hookInput, withEmit, {
|
|
4758
|
+
phase: "prepare"
|
|
4759
|
+
}) : void 0) ?? {
|
|
4760
|
+
status: "ready"
|
|
4761
|
+
};
|
|
4762
|
+
if (options.snapshotInput === true) assertTrustedInput(name, hookInput, normalized);
|
|
4763
|
+
return {
|
|
4764
|
+
input: normalized,
|
|
4765
|
+
preflight
|
|
4766
|
+
};
|
|
4767
|
+
}
|
|
4768
|
+
async validated(name, input, ctx, policy, options) {
|
|
2955
4769
|
const entry = this.entries.get(name);
|
|
2956
4770
|
if (entry === void 0) {
|
|
2957
4771
|
throw new ToolNotFoundError(name);
|
|
@@ -2976,7 +4790,11 @@ var ToolRegistry = class {
|
|
|
2976
4790
|
...ctx,
|
|
2977
4791
|
emitUi: createNoopEmitUi(ctx.requestId)
|
|
2978
4792
|
};
|
|
2979
|
-
return
|
|
4793
|
+
return {
|
|
4794
|
+
entry,
|
|
4795
|
+
value: validation.value,
|
|
4796
|
+
ctx: withEmit
|
|
4797
|
+
};
|
|
2980
4798
|
}
|
|
2981
4799
|
};
|
|
2982
4800
|
var DefaultRolesPolicy = class {
|
|
@@ -2991,6 +4809,7 @@ var DefaultRolesPolicy = class {
|
|
|
2991
4809
|
this.emptyRoles = options.emptyRoles ?? "allow";
|
|
2992
4810
|
}
|
|
2993
4811
|
can(actor, tool) {
|
|
4812
|
+
if (tool.ability !== void 0 && tool.roles === void 0) return false;
|
|
2994
4813
|
const allowed = tool.roles ?? this.defaultRoles;
|
|
2995
4814
|
if (allowed.length === 0) return this.emptyRoles === "allow";
|
|
2996
4815
|
return (actor.roles ?? []).some((role) => allowed.includes(role));
|
|
@@ -3023,6 +4842,69 @@ __name(closeEmptyRoles, "closeEmptyRoles");
|
|
|
3023
4842
|
var import_node_crypto = require("crypto");
|
|
3024
4843
|
var import_nestjs_diagnostics2 = require("@dudousxd/nestjs-diagnostics");
|
|
3025
4844
|
|
|
4845
|
+
// src/action-proposal-approval.ts
|
|
4846
|
+
async function resolveActionProposalApproval(input) {
|
|
4847
|
+
const policy = input.policy ?? new DefaultApprovalPolicy();
|
|
4848
|
+
const requirement = await policy.requirementFor(input.tool, input.actor, input.thread);
|
|
4849
|
+
if (!requirement.required) return {
|
|
4850
|
+
mode: "auto"
|
|
4851
|
+
};
|
|
4852
|
+
const remembered = await input.store.rememberedApprovals?.(input.thread.threadId) ?? [];
|
|
4853
|
+
if (remembered.includes(input.tool.name)) return {
|
|
4854
|
+
mode: "remembered",
|
|
4855
|
+
approver: requirement.approver
|
|
4856
|
+
};
|
|
4857
|
+
const roundedTtl = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) ? Math.floor(requirement.ttlMs) : 0;
|
|
4858
|
+
if (roundedTtl <= 0) return {
|
|
4859
|
+
mode: "ask",
|
|
4860
|
+
approver: requirement.approver
|
|
4861
|
+
};
|
|
4862
|
+
const now = (input.clock ?? Date.now)();
|
|
4863
|
+
if (!Number.isSafeInteger(now) || !Number.isSafeInteger(roundedTtl) || !Number.isSafeInteger(now + roundedTtl)) throw new RangeError("Invalid action approval deadline");
|
|
4864
|
+
return {
|
|
4865
|
+
mode: "ask",
|
|
4866
|
+
approver: requirement.approver,
|
|
4867
|
+
ttlMs: roundedTtl,
|
|
4868
|
+
expiresAt: new Date(now + roundedTtl).toISOString()
|
|
4869
|
+
};
|
|
4870
|
+
}
|
|
4871
|
+
__name(resolveActionProposalApproval, "resolveActionProposalApproval");
|
|
4872
|
+
|
|
4873
|
+
// src/action-proposal-preparation.ts
|
|
4874
|
+
async function prepareActionProposal(registry, name, input, ctx, policy, options = {}) {
|
|
4875
|
+
const preparationInput = snapshotActionProposal(input);
|
|
4876
|
+
const prepared = await registry.prepareValidated(name, snapshotActionProposal(preparationInput), ctx, policy, {
|
|
4877
|
+
...options,
|
|
4878
|
+
snapshotInput: true
|
|
4879
|
+
});
|
|
4880
|
+
let replacementKey;
|
|
4881
|
+
const replacement = registry.spec(name)?.replacementKey;
|
|
4882
|
+
if (prepared.preflight.status === "ready" && replacement !== void 0) {
|
|
4883
|
+
replacementKey = typeof replacement === "string" ? replacement : await replacement(snapshotActionProposal(prepared.input), ctx);
|
|
4884
|
+
if (replacementKey !== void 0 && (typeof replacementKey !== "string" || !replacementKey || replacementKey.length > 255)) throw new TypeError("replacementKey must be a nonempty string of at most 255 UTF-16 code units");
|
|
4885
|
+
}
|
|
4886
|
+
return {
|
|
4887
|
+
...replacementKey !== void 0 ? {
|
|
4888
|
+
replacementKey
|
|
4889
|
+
} : {},
|
|
4890
|
+
preparationInput,
|
|
4891
|
+
input: prepared.input,
|
|
4892
|
+
// Completed results keep their normal handler contract; they never create a proposal.
|
|
4893
|
+
preflight: prepared.preflight.status === "ready" ? snapshotActionProposal(prepared.preflight) : prepared.preflight
|
|
4894
|
+
};
|
|
4895
|
+
}
|
|
4896
|
+
__name(prepareActionProposal, "prepareActionProposal");
|
|
4897
|
+
|
|
4898
|
+
// src/action-proposal-receipt.ts
|
|
4899
|
+
function actionProposalReceipt(proposalId) {
|
|
4900
|
+
return {
|
|
4901
|
+
proposalId,
|
|
4902
|
+
status: "pending",
|
|
4903
|
+
executed: false
|
|
4904
|
+
};
|
|
4905
|
+
}
|
|
4906
|
+
__name(actionProposalReceipt, "actionProposalReceipt");
|
|
4907
|
+
|
|
3026
4908
|
// src/diagnostics.ts
|
|
3027
4909
|
var import_nestjs_diagnostics = require("@dudousxd/nestjs-diagnostics");
|
|
3028
4910
|
function publishAgentRunStarted(payload) {
|
|
@@ -3077,7 +4959,8 @@ var AGENT_SPAN_EVENTS = [
|
|
|
3077
4959
|
"llm.turn",
|
|
3078
4960
|
"tool.execution",
|
|
3079
4961
|
"retrieval",
|
|
3080
|
-
"follow-ups"
|
|
4962
|
+
"follow-ups",
|
|
4963
|
+
"structured-output"
|
|
3081
4964
|
];
|
|
3082
4965
|
var AGENT_DIAGNOSTIC_EVENTS = [
|
|
3083
4966
|
"run.started",
|
|
@@ -3098,6 +4981,67 @@ function agentDiagnosticKey(event) {
|
|
|
3098
4981
|
}
|
|
3099
4982
|
__name(agentDiagnosticKey, "agentDiagnosticKey");
|
|
3100
4983
|
|
|
4984
|
+
// src/negotiated-tool-ui.ts
|
|
4985
|
+
function createNegotiatedUiCollector(toolCallId, scope, resolveCatalog, write) {
|
|
4986
|
+
const collector = createUiCollector(toolCallId, write);
|
|
4987
|
+
const texts = /* @__PURE__ */ new Map();
|
|
4988
|
+
let next = 0;
|
|
4989
|
+
return {
|
|
4990
|
+
components: collector.components,
|
|
4991
|
+
text: /* @__PURE__ */ __name(() => [
|
|
4992
|
+
...texts.values()
|
|
4993
|
+
].join("\n"), "text"),
|
|
4994
|
+
restart: /* @__PURE__ */ __name(() => {
|
|
4995
|
+
next = 0;
|
|
4996
|
+
texts.clear();
|
|
4997
|
+
collector.restart();
|
|
4998
|
+
}, "restart"),
|
|
4999
|
+
emit: /* @__PURE__ */ __name(async (component, props, options = {}) => {
|
|
5000
|
+
if (!resolveCatalog) {
|
|
5001
|
+
const declared = scope.uiCapabilities === void 0 || scope.uiCapabilities.components.some((entry) => entry.name === component && entry.version === (options.version ?? 1));
|
|
5002
|
+
if (declared) return collector.emit(component, props, options);
|
|
5003
|
+
const id2 = options.id ?? `${toolCallId}:ui:${next++}`;
|
|
5004
|
+
if (options.fallbackText !== void 0 && options.fallbackText.length > 0) {
|
|
5005
|
+
texts.set(id2, options.fallbackText);
|
|
5006
|
+
await write?.({
|
|
5007
|
+
kind: "text",
|
|
5008
|
+
text: options.fallbackText
|
|
5009
|
+
});
|
|
5010
|
+
}
|
|
5011
|
+
return {
|
|
5012
|
+
id: id2
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
5015
|
+
const capturedProps = snapshotActionProposal(props);
|
|
5016
|
+
const capturedOptions = {
|
|
5017
|
+
...options
|
|
5018
|
+
};
|
|
5019
|
+
const catalog = await resolveCatalog(scope);
|
|
5020
|
+
const prepared = await prepareUiEmission(catalog, scope.uiCapabilities, component, capturedProps, capturedOptions.version);
|
|
5021
|
+
const id = capturedOptions.id ?? `${toolCallId}:ui:${next++}`;
|
|
5022
|
+
if (prepared.kind === "text") {
|
|
5023
|
+
texts.set(id, prepared.text);
|
|
5024
|
+
await write?.({
|
|
5025
|
+
kind: "text",
|
|
5026
|
+
text: prepared.text
|
|
5027
|
+
});
|
|
5028
|
+
return {
|
|
5029
|
+
id
|
|
5030
|
+
};
|
|
5031
|
+
}
|
|
5032
|
+
return collector.emit(prepared.component, prepared.props, {
|
|
5033
|
+
id,
|
|
5034
|
+
version: prepared.version,
|
|
5035
|
+
fallbackText: prepared.fallbackText,
|
|
5036
|
+
...prepared.componentVersions !== void 0 ? {
|
|
5037
|
+
componentVersions: prepared.componentVersions
|
|
5038
|
+
} : {}
|
|
5039
|
+
});
|
|
5040
|
+
}, "emit")
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
__name(createNegotiatedUiCollector, "createNegotiatedUiCollector");
|
|
5044
|
+
|
|
3101
5045
|
// src/tool-retry.ts
|
|
3102
5046
|
function hasTransientShape(error) {
|
|
3103
5047
|
if (typeof error !== "object" || error === null) {
|
|
@@ -3123,6 +5067,7 @@ function hasTransientShape(error) {
|
|
|
3123
5067
|
}
|
|
3124
5068
|
__name(hasTransientShape, "hasTransientShape");
|
|
3125
5069
|
function isTransientToolError(error) {
|
|
5070
|
+
if (error instanceof ToolPreflightDeniedError) return false;
|
|
3126
5071
|
if (hasTransientShape(error)) {
|
|
3127
5072
|
return true;
|
|
3128
5073
|
}
|
|
@@ -3165,7 +5110,7 @@ async function invokeWithTransientRetry(fn, setting, options) {
|
|
|
3165
5110
|
try {
|
|
3166
5111
|
return await fn();
|
|
3167
5112
|
} catch (error) {
|
|
3168
|
-
if (isControlFlowSignal(error) || options?.isControlFlowError?.(error) === true) {
|
|
5113
|
+
if (error instanceof ToolPreflightDeniedError || isControlFlowSignal(error) || options?.isControlFlowError?.(error) === true) {
|
|
3169
5114
|
throw error;
|
|
3170
5115
|
}
|
|
3171
5116
|
const attemptsRemain = attempt < attempts;
|
|
@@ -3345,6 +5290,9 @@ function promptContext(input, persona) {
|
|
|
3345
5290
|
...input.pageContext !== void 0 ? {
|
|
3346
5291
|
pageContext: input.pageContext
|
|
3347
5292
|
} : {},
|
|
5293
|
+
...input.uiCapabilities !== void 0 ? {
|
|
5294
|
+
uiCapabilities: input.uiCapabilities
|
|
5295
|
+
} : {},
|
|
3348
5296
|
...persona !== void 0 ? {
|
|
3349
5297
|
persona: {
|
|
3350
5298
|
id: persona.id,
|
|
@@ -3541,7 +5489,8 @@ async function loadSelectedHistory(deps, input, hooks) {
|
|
|
3541
5489
|
messages: keep,
|
|
3542
5490
|
dropped: deps.historyPolicy?.summarize === void 0 ? [] : drop,
|
|
3543
5491
|
title: thread.title,
|
|
3544
|
-
hasAssistantMessage: thread.hasAssistantMessage
|
|
5492
|
+
hasAssistantMessage: thread.hasAssistantMessage,
|
|
5493
|
+
actionApprovalMode: deps.actionApprovalMode ?? "blocking"
|
|
3545
5494
|
};
|
|
3546
5495
|
});
|
|
3547
5496
|
return {
|
|
@@ -3705,10 +5654,10 @@ async function structureAnswer(schema, deps, input, hooks, messages, step) {
|
|
|
3705
5654
|
modelId: turn.modelId
|
|
3706
5655
|
} : {}
|
|
3707
5656
|
};
|
|
3708
|
-
}, (
|
|
3709
|
-
inputTokens:
|
|
3710
|
-
outputTokens:
|
|
3711
|
-
textLength:
|
|
5657
|
+
}, (result2) => ({
|
|
5658
|
+
inputTokens: result2.usage.inputTokens,
|
|
5659
|
+
outputTokens: result2.usage.outputTokens,
|
|
5660
|
+
textLength: result2.text.length
|
|
3712
5661
|
})));
|
|
3713
5662
|
await hooks.step(`persist:usage:structured:${step}:${attempt}`, () => deps.store.recordUsage({
|
|
3714
5663
|
threadId: input.threadId,
|
|
@@ -3738,13 +5687,16 @@ async function structureAnswer(schema, deps, input, hooks, messages, step) {
|
|
|
3738
5687
|
throw new StructuredOutputError(issues, text, maxAttempts);
|
|
3739
5688
|
}
|
|
3740
5689
|
__name(structureAnswer, "structureAnswer");
|
|
3741
|
-
function stampToolKinds(
|
|
5690
|
+
function stampToolKinds(result2, deps) {
|
|
3742
5691
|
return {
|
|
3743
|
-
...
|
|
3744
|
-
toolCalls:
|
|
3745
|
-
...call
|
|
3746
|
-
kind
|
|
3747
|
-
|
|
5692
|
+
...result2,
|
|
5693
|
+
toolCalls: result2.toolCalls.map((call) => {
|
|
5694
|
+
const { preflight: _untrusted, prepared: _untrustedPrepared, actionApproval: _untrustedApproval, ...trusted } = call;
|
|
5695
|
+
return trusted.kind === void 0 ? {
|
|
5696
|
+
...trusted,
|
|
5697
|
+
kind: declaredKind(deps, trusted.name)
|
|
5698
|
+
} : trusted;
|
|
5699
|
+
})
|
|
3748
5700
|
};
|
|
3749
5701
|
}
|
|
3750
5702
|
__name(stampToolKinds, "stampToolKinds");
|
|
@@ -3807,6 +5759,9 @@ function toolContext(deps, input, hooks) {
|
|
|
3807
5759
|
...input.pageContext !== void 0 ? {
|
|
3808
5760
|
pageContext: input.pageContext
|
|
3809
5761
|
} : {},
|
|
5762
|
+
...input.uiCapabilities !== void 0 ? {
|
|
5763
|
+
uiCapabilities: input.uiCapabilities
|
|
5764
|
+
} : {},
|
|
3810
5765
|
...deps.host !== void 0 ? {
|
|
3811
5766
|
host: deps.host
|
|
3812
5767
|
} : {},
|
|
@@ -3882,16 +5837,16 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3882
5837
|
}
|
|
3883
5838
|
const messageId = asked.messageId;
|
|
3884
5839
|
const reply = await awaitElicitation(hooks, request, toolContext(deps, input, hooks));
|
|
3885
|
-
const
|
|
5840
|
+
const result2 = settleElicitation(request, reply);
|
|
3886
5841
|
await hooks.step("intake:answers", async () => {
|
|
3887
5842
|
await deps.store.updateToolCall({
|
|
3888
5843
|
toolCallId: request.id,
|
|
3889
5844
|
// A skip is not an answer. Both leave the agent holding the same values, but only one of them
|
|
3890
5845
|
// is evidence the user chose them, and a reader auditing what the agent was told has to be
|
|
3891
5846
|
// able to tell those apart.
|
|
3892
|
-
status:
|
|
3893
|
-
output:
|
|
3894
|
-
...
|
|
5847
|
+
status: result2.skipped ? "rejected" : "executed",
|
|
5848
|
+
output: result2,
|
|
5849
|
+
...result2.skipped ? {
|
|
3895
5850
|
error: "skipped by the user"
|
|
3896
5851
|
} : {},
|
|
3897
5852
|
...reply.answeredByRef !== void 0 ? {
|
|
@@ -3902,13 +5857,13 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3902
5857
|
{
|
|
3903
5858
|
id: request.id,
|
|
3904
5859
|
name: ASK_TOOL_NAME,
|
|
3905
|
-
output:
|
|
5860
|
+
output: result2
|
|
3906
5861
|
}
|
|
3907
5862
|
]);
|
|
3908
5863
|
await writer.write(encodeStreamEvent({
|
|
3909
5864
|
kind: "tool-output",
|
|
3910
5865
|
id: request.id,
|
|
3911
|
-
output:
|
|
5866
|
+
output: result2
|
|
3912
5867
|
}));
|
|
3913
5868
|
});
|
|
3914
5869
|
return {
|
|
@@ -3921,7 +5876,7 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3921
5876
|
{
|
|
3922
5877
|
id: request.id,
|
|
3923
5878
|
name: ASK_TOOL_NAME,
|
|
3924
|
-
output:
|
|
5879
|
+
output: result2
|
|
3925
5880
|
}
|
|
3926
5881
|
]
|
|
3927
5882
|
};
|
|
@@ -3967,16 +5922,140 @@ async function claimToolCall(turn, call) {
|
|
|
3967
5922
|
const spec = deps.registry.spec(call.name);
|
|
3968
5923
|
const kind = call.kind ?? declaredKind(deps, call.name);
|
|
3969
5924
|
const awaitsHuman = kind === "action" || kind === "ask";
|
|
3970
|
-
const
|
|
3971
|
-
|
|
5925
|
+
const independentApproval = turn.actionApprovalMode === "independent" && kind === "action" ? hooks.dispatchLlm !== void 0 && call.actionApproval !== void 0 ? call.actionApproval : await resolveActionProposalApproval({
|
|
5926
|
+
actor: input.actor,
|
|
5927
|
+
store: deps.store,
|
|
5928
|
+
tool: {
|
|
5929
|
+
name: call.name,
|
|
5930
|
+
kind: "action",
|
|
5931
|
+
...spec !== void 0 ? {
|
|
5932
|
+
spec
|
|
5933
|
+
} : {}
|
|
5934
|
+
},
|
|
5935
|
+
thread: {
|
|
5936
|
+
threadId: input.threadId,
|
|
5937
|
+
runId: hooks.runId,
|
|
5938
|
+
...input.agentName !== void 0 ? {
|
|
5939
|
+
agentName: input.agentName
|
|
5940
|
+
} : {}
|
|
5941
|
+
},
|
|
5942
|
+
...deps.approvalPolicy !== void 0 ? {
|
|
5943
|
+
policy: deps.approvalPolicy
|
|
5944
|
+
} : {}
|
|
5945
|
+
}) : void 0;
|
|
5946
|
+
let preflight;
|
|
5947
|
+
let prepared;
|
|
5948
|
+
if (turn.actionApprovalMode === "independent" && call.prepared !== void 0 && hooks.dispatchLlm !== void 0) prepared = call.prepared;
|
|
5949
|
+
if (kind === "action" && hooks.dispatchLlm !== void 0 && call.preflight !== void 0) {
|
|
5950
|
+
preflight = call.preflight;
|
|
5951
|
+
} else if (kind === "action" && hooks.dispatchLlm !== void 0 && spec === void 0) {
|
|
5952
|
+
preflight = {
|
|
5953
|
+
status: "ready"
|
|
5954
|
+
};
|
|
5955
|
+
} else if (kind === "action") {
|
|
5956
|
+
try {
|
|
5957
|
+
const allowedTools = turn.persona?.allowedTools === void 0 ? deps.toolAllowList : intersectAllowLists(deps.toolAllowList, turn.persona.allowedTools);
|
|
5958
|
+
if (independentApproval?.mode === "ask") {
|
|
5959
|
+
prepared = await prepareActionProposal(deps.registry, call.name, call.input, toolCallContext(toolContext(deps, input, hooks), call.id), deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
5960
|
+
allowedTools
|
|
5961
|
+
});
|
|
5962
|
+
preflight = prepared.preflight;
|
|
5963
|
+
} else {
|
|
5964
|
+
preflight = await deps.registry.prepare(call.name, call.input, toolCallContext(toolContext(deps, input, hooks), call.id), deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
5965
|
+
allowedTools
|
|
5966
|
+
});
|
|
5967
|
+
}
|
|
5968
|
+
} catch (error) {
|
|
5969
|
+
if (hooks.isControlFlowError?.(error) === true || isControlFlowSignal(error) || isReplayIntegrityError(error)) throw error;
|
|
5970
|
+
preflight = {
|
|
5971
|
+
status: "failed",
|
|
5972
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5973
|
+
};
|
|
5974
|
+
}
|
|
5975
|
+
}
|
|
5976
|
+
let confirmation = preflight?.status === "ready" ? preflight.confirmation : void 0;
|
|
5977
|
+
const approval = kind === "action" && preflight?.status === "ready" ? independentApproval ?? await claimApproval(turn, call, spec) : void 0;
|
|
5978
|
+
let proposalId;
|
|
5979
|
+
if (turn.actionApprovalMode === "independent" && approval?.mode === "ask") {
|
|
5980
|
+
if (!prepared) throw new Error("Independent action lacks trusted prepared input");
|
|
5981
|
+
const proposalStore = deps.store;
|
|
5982
|
+
if (typeof proposalStore.createActionProposal !== "function") throw new Error("Independent action proposal store unavailable");
|
|
5983
|
+
proposalId = `proposal-${(0, import_node_crypto.createHash)("sha256").update(JSON.stringify([
|
|
5984
|
+
hooks.runId,
|
|
5985
|
+
call.id
|
|
5986
|
+
])).digest("hex")}`;
|
|
5987
|
+
const display = confirmation ?? spec?.presentation?.confirm ?? {
|
|
5988
|
+
title: `Allow ${call.name}?`,
|
|
5989
|
+
verb: "Approve"
|
|
5990
|
+
};
|
|
5991
|
+
const fill = /* @__PURE__ */ __name((value) => value.replace(/\{([^}]+)\}/g, (_match, path) => {
|
|
5992
|
+
let current = prepared?.input;
|
|
5993
|
+
for (const part of path.split(".")) current = current !== null && typeof current === "object" ? current[part] : void 0;
|
|
5994
|
+
return current === void 0 ? "" : String(current);
|
|
5995
|
+
}), "fill");
|
|
5996
|
+
const create = prepared.replacementKey === void 0 ? proposalStore.createActionProposal.bind(proposalStore) : (() => {
|
|
5997
|
+
const store = proposalStore;
|
|
5998
|
+
if (typeof store.createReplacingActionProposal !== "function") throw new Error("Independent replacement requires atomic supersession store");
|
|
5999
|
+
return store.createReplacingActionProposal.bind(store);
|
|
6000
|
+
})();
|
|
6001
|
+
const created = await create({
|
|
6002
|
+
...prepared.replacementKey !== void 0 ? {
|
|
6003
|
+
replacementKey: prepared.replacementKey
|
|
6004
|
+
} : {},
|
|
6005
|
+
id: proposalId,
|
|
6006
|
+
tenantRef: input.actor.tenantRef ?? null,
|
|
6007
|
+
actorRef: input.actor.id,
|
|
6008
|
+
threadId: input.threadId,
|
|
6009
|
+
originRunId: hooks.runId,
|
|
6010
|
+
originMessageId: messageId,
|
|
6011
|
+
originToolCallId: call.id,
|
|
6012
|
+
toolName: call.name,
|
|
6013
|
+
input: prepared.input,
|
|
6014
|
+
preparationInput: prepared.preparationInput,
|
|
6015
|
+
executionContext: {
|
|
6016
|
+
requestId: hooks.runId,
|
|
6017
|
+
...input.agentName !== void 0 ? {
|
|
6018
|
+
agentName: input.agentName
|
|
6019
|
+
} : {},
|
|
6020
|
+
...input.persona !== void 0 ? {
|
|
6021
|
+
persona: input.persona
|
|
6022
|
+
} : {},
|
|
6023
|
+
...input.pageContext !== void 0 ? {
|
|
6024
|
+
pageContext: input.pageContext
|
|
6025
|
+
} : {},
|
|
6026
|
+
...input.uiCapabilities !== void 0 ? {
|
|
6027
|
+
uiCapabilities: input.uiCapabilities
|
|
6028
|
+
} : {}
|
|
6029
|
+
},
|
|
6030
|
+
confirmation: confirmation ?? {
|
|
6031
|
+
title: fill(display.title),
|
|
6032
|
+
verb: fill(display.verb),
|
|
6033
|
+
...display.detail !== void 0 ? {
|
|
6034
|
+
detail: fill(display.detail)
|
|
6035
|
+
} : {}
|
|
6036
|
+
},
|
|
6037
|
+
approver: approval.approver,
|
|
6038
|
+
expiresAt: approval.expiresAt === void 0 ? null : Date.parse(approval.expiresAt),
|
|
6039
|
+
idempotencyKey: toolCallContext(toolContext(deps, input, hooks), call.id).idempotencyKey
|
|
6040
|
+
});
|
|
6041
|
+
if (created.status === "conflict") throw new Error("Action proposal replay payload conflict");
|
|
6042
|
+
confirmation = created.proposal?.confirmation ?? confirmation;
|
|
6043
|
+
}
|
|
6044
|
+
const parks = kind === "ask" || approval?.mode === "ask" && proposalId === void 0;
|
|
3972
6045
|
await deps.store.recordToolCall({
|
|
3973
6046
|
toolCallId: call.id,
|
|
3974
6047
|
messageId,
|
|
3975
6048
|
toolName: call.name,
|
|
3976
6049
|
toolType: awaitsHuman ? "action" : "read",
|
|
3977
6050
|
input: call.input,
|
|
3978
|
-
status: parks ? "pending_approval" : "auto_executed",
|
|
6051
|
+
status: proposalId !== void 0 ? "proposed" : parks ? "pending_approval" : "auto_executed",
|
|
6052
|
+
...proposalId !== void 0 ? {
|
|
6053
|
+
proposalId
|
|
6054
|
+
} : {},
|
|
3979
6055
|
runId: hooks.runId,
|
|
6056
|
+
...confirmation !== void 0 ? {
|
|
6057
|
+
confirmation
|
|
6058
|
+
} : {},
|
|
3980
6059
|
...approval !== void 0 && approval.mode !== "auto" ? {
|
|
3981
6060
|
approver: approval.approver
|
|
3982
6061
|
} : {},
|
|
@@ -3988,7 +6067,16 @@ async function claimToolCall(turn, call) {
|
|
|
3988
6067
|
await turn.writer.write(encodeStreamEvent({
|
|
3989
6068
|
kind: "approval-requested",
|
|
3990
6069
|
id: call.id,
|
|
6070
|
+
...proposalId !== void 0 ? {
|
|
6071
|
+
target: {
|
|
6072
|
+
kind: "proposal",
|
|
6073
|
+
proposalId
|
|
6074
|
+
}
|
|
6075
|
+
} : {},
|
|
3991
6076
|
approver: approval.approver,
|
|
6077
|
+
...confirmation !== void 0 ? {
|
|
6078
|
+
confirmation
|
|
6079
|
+
} : {},
|
|
3992
6080
|
...approval.expiresAt !== void 0 ? {
|
|
3993
6081
|
expiresAt: approval.expiresAt
|
|
3994
6082
|
} : {}
|
|
@@ -4009,8 +6097,18 @@ async function claimToolCall(turn, call) {
|
|
|
4009
6097
|
...spec?.terminal === true ? {
|
|
4010
6098
|
terminal: true
|
|
4011
6099
|
} : {},
|
|
6100
|
+
// Journal this extra checkpoint's opt-in; historical claims without it keep their sequence.
|
|
6101
|
+
...preflight?.status === "completed" && deps.registry.hasPresentation(call.name) ? {
|
|
6102
|
+
presentCompletedPreflight: true
|
|
6103
|
+
} : {},
|
|
4012
6104
|
...approval !== void 0 ? {
|
|
4013
6105
|
approval
|
|
6106
|
+
} : {},
|
|
6107
|
+
...preflight !== void 0 ? {
|
|
6108
|
+
preflight
|
|
6109
|
+
} : {},
|
|
6110
|
+
...proposalId !== void 0 ? {
|
|
6111
|
+
proposalId
|
|
4014
6112
|
} : {}
|
|
4015
6113
|
};
|
|
4016
6114
|
});
|
|
@@ -4033,9 +6131,18 @@ async function claimToolCall(turn, call) {
|
|
|
4033
6131
|
...persisted?.terminal === true ? {
|
|
4034
6132
|
terminal: true
|
|
4035
6133
|
} : {},
|
|
6134
|
+
...persisted?.presentCompletedPreflight === true ? {
|
|
6135
|
+
presentCompletedPreflight: true
|
|
6136
|
+
} : {},
|
|
4036
6137
|
...toolType === "action" && persisted?.approval !== void 0 ? {
|
|
4037
6138
|
approval: persisted.approval
|
|
4038
6139
|
} : {},
|
|
6140
|
+
...persisted?.preflight !== void 0 ? {
|
|
6141
|
+
preflight: persisted.preflight
|
|
6142
|
+
} : {},
|
|
6143
|
+
...persisted?.proposalId !== void 0 ? {
|
|
6144
|
+
proposalId: persisted.proposalId
|
|
6145
|
+
} : {},
|
|
4039
6146
|
ctx: toolContext(deps, input, hooks)
|
|
4040
6147
|
};
|
|
4041
6148
|
}
|
|
@@ -4183,6 +6290,9 @@ function skillContext(input) {
|
|
|
4183
6290
|
} : {},
|
|
4184
6291
|
...input.pageContext !== void 0 ? {
|
|
4185
6292
|
pageContext: input.pageContext
|
|
6293
|
+
} : {},
|
|
6294
|
+
...input.uiCapabilities !== void 0 ? {
|
|
6295
|
+
uiCapabilities: input.uiCapabilities
|
|
4186
6296
|
} : {}
|
|
4187
6297
|
};
|
|
4188
6298
|
}
|
|
@@ -4199,7 +6309,7 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4199
6309
|
if (claimed.toolType === "memory") {
|
|
4200
6310
|
return await rememberIntoTurn(turn, claimed, startedAt);
|
|
4201
6311
|
}
|
|
4202
|
-
const invokeAllowList = turn.persona?.allowedTools === void 0 ?
|
|
6312
|
+
const invokeAllowList = turn.persona?.allowedTools === void 0 ? deps.toolAllowList : intersectAllowLists(deps.toolAllowList, turn.persona.allowedTools);
|
|
4203
6313
|
let raw;
|
|
4204
6314
|
if (hooks.dispatchTool) {
|
|
4205
6315
|
const stepCtx = {
|
|
@@ -4215,6 +6325,9 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4215
6325
|
} : {},
|
|
4216
6326
|
...input.pageContext !== void 0 ? {
|
|
4217
6327
|
pageContext: input.pageContext
|
|
6328
|
+
} : {},
|
|
6329
|
+
...input.uiCapabilities !== void 0 ? {
|
|
6330
|
+
uiCapabilities: input.uiCapabilities
|
|
4218
6331
|
} : {}
|
|
4219
6332
|
};
|
|
4220
6333
|
const envelope = {
|
|
@@ -4236,37 +6349,49 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4236
6349
|
raw = await hooks.dispatchTool(resolvedCall, envelope);
|
|
4237
6350
|
} else {
|
|
4238
6351
|
const invocation = hooks.step(`tool:${call.id}`, async () => {
|
|
4239
|
-
const ui2 =
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
6352
|
+
const ui2 = createNegotiatedUiCollector(call.id, ctx, deps.resolveUiCatalog, (event) => turn.writer.write(encodeStreamEvent(event)));
|
|
6353
|
+
let output2;
|
|
6354
|
+
try {
|
|
6355
|
+
output2 = await traceToolExecution(hooks.runId, {
|
|
6356
|
+
toolCallId: call.id,
|
|
6357
|
+
toolName: call.name,
|
|
6358
|
+
toolType
|
|
6359
|
+
}, () => invokeWithTransientRetry(() => {
|
|
6360
|
+
ui2.restart();
|
|
6361
|
+
return deps.registry.invoke(call.name, call.input, {
|
|
6362
|
+
...toolCallContext(ctx, call.id),
|
|
6363
|
+
emitUi: ui2.emit
|
|
6364
|
+
}, deps.rolesPolicy, invokeAllowList !== void 0 ? {
|
|
6365
|
+
allowedTools: invokeAllowList
|
|
6366
|
+
} : {});
|
|
6367
|
+
}, deps.toolTransientRetry ?? {}, {
|
|
6368
|
+
...hooks.isControlFlowError !== void 0 ? {
|
|
6369
|
+
isControlFlowError: hooks.isControlFlowError
|
|
6370
|
+
} : {},
|
|
6371
|
+
onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
|
|
6372
|
+
publishAgentToolRetry({
|
|
6373
|
+
toolName: call.name,
|
|
6374
|
+
toolCallId: call.id,
|
|
6375
|
+
attempt,
|
|
6376
|
+
message: retryError instanceof Error ? retryError.message : String(retryError)
|
|
6377
|
+
});
|
|
6378
|
+
}, "onRetry")
|
|
6379
|
+
}));
|
|
6380
|
+
} catch (error) {
|
|
6381
|
+
if (error instanceof Error && error.name === "ToolPreflightDeniedError") return wrapToolPreflightDenied(error.message);
|
|
6382
|
+
throw error;
|
|
6383
|
+
}
|
|
6384
|
+
return wrapToolStepOutput(output2, ui2.components(), ui2.text());
|
|
4266
6385
|
});
|
|
4267
6386
|
raw = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
|
|
4268
6387
|
}
|
|
4269
|
-
const { output, ui } = unwrapToolStepOutput(raw);
|
|
6388
|
+
const { output, ui, preflightDenied, text } = unwrapToolStepOutput(raw);
|
|
6389
|
+
if (text) turn.toolText.set(call.id, text);
|
|
6390
|
+
if (preflightDenied !== void 0) return {
|
|
6391
|
+
status: "denied",
|
|
6392
|
+
reason: preflightDenied,
|
|
6393
|
+
executionMs: Date.now() - startedAt
|
|
6394
|
+
};
|
|
4270
6395
|
if (ui.length > 0) {
|
|
4271
6396
|
turn.toolUi.set(call.id, ui);
|
|
4272
6397
|
}
|
|
@@ -4282,6 +6407,13 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4282
6407
|
if (hooks.isControlFlowError?.(error) === true || isControlFlowSignal(error) || isReplayIntegrityError(error)) {
|
|
4283
6408
|
throw error;
|
|
4284
6409
|
}
|
|
6410
|
+
if (error instanceof Error && error.name === "ToolPreflightDeniedError") {
|
|
6411
|
+
return {
|
|
6412
|
+
status: "denied",
|
|
6413
|
+
reason: error.message,
|
|
6414
|
+
executionMs: Date.now() - startedAt
|
|
6415
|
+
};
|
|
6416
|
+
}
|
|
4285
6417
|
return {
|
|
4286
6418
|
status: "failed",
|
|
4287
6419
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -4323,6 +6455,27 @@ async function recordToolOutcome(turn, claimed, outcome, deciderRef, meta) {
|
|
|
4323
6455
|
} : {}
|
|
4324
6456
|
}));
|
|
4325
6457
|
}, "settle");
|
|
6458
|
+
if (outcome.status === "denied") {
|
|
6459
|
+
await hooks.step(`persist:toolreject:${call.id}`, async () => {
|
|
6460
|
+
await deps.store.updateToolCall({
|
|
6461
|
+
toolCallId: call.id,
|
|
6462
|
+
status: meta === void 0 ? "rejected" : "failed",
|
|
6463
|
+
error: outcome.reason,
|
|
6464
|
+
...decided
|
|
6465
|
+
});
|
|
6466
|
+
await settle();
|
|
6467
|
+
});
|
|
6468
|
+
return {
|
|
6469
|
+
id: call.id,
|
|
6470
|
+
name: call.name,
|
|
6471
|
+
output: {
|
|
6472
|
+
rejected: true,
|
|
6473
|
+
reason: outcome.reason
|
|
6474
|
+
},
|
|
6475
|
+
denied: true,
|
|
6476
|
+
error: `This action was denied by its preflight check: ${outcome.reason}. The requested mutation did not run.`
|
|
6477
|
+
};
|
|
6478
|
+
}
|
|
4326
6479
|
if (outcome.status === "failed") {
|
|
4327
6480
|
await hooks.step(`persist:toolfail:${call.id}`, async () => {
|
|
4328
6481
|
await deps.store.updateToolCall({
|
|
@@ -4463,12 +6616,12 @@ async function elicitToolCall(turn, claimed) {
|
|
|
4463
6616
|
}));
|
|
4464
6617
|
});
|
|
4465
6618
|
const reply = await awaitElicitation(hooks, request, ctx);
|
|
4466
|
-
const
|
|
4467
|
-
await hooks.step(
|
|
6619
|
+
const result2 = settleElicitation(request, reply);
|
|
6620
|
+
await hooks.step(result2.skipped ? `persist:toolreject:${call.id}` : `persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
|
|
4468
6621
|
toolCallId: call.id,
|
|
4469
|
-
status:
|
|
4470
|
-
output:
|
|
4471
|
-
...
|
|
6622
|
+
status: result2.skipped ? "rejected" : "executed",
|
|
6623
|
+
output: result2,
|
|
6624
|
+
...result2.skipped ? {
|
|
4472
6625
|
error: "skipped by the user"
|
|
4473
6626
|
} : {},
|
|
4474
6627
|
...reply.answeredByRef !== void 0 ? {
|
|
@@ -4479,24 +6632,63 @@ async function elicitToolCall(turn, claimed) {
|
|
|
4479
6632
|
runId: hooks.runId,
|
|
4480
6633
|
toolName: call.name,
|
|
4481
6634
|
toolType: "action",
|
|
4482
|
-
status:
|
|
6635
|
+
status: result2.skipped ? "rejected" : "executed"
|
|
4483
6636
|
});
|
|
4484
6637
|
return {
|
|
4485
6638
|
id: call.id,
|
|
4486
6639
|
name: call.name,
|
|
4487
|
-
output:
|
|
6640
|
+
output: result2
|
|
4488
6641
|
};
|
|
4489
6642
|
}
|
|
4490
6643
|
__name(elicitToolCall, "elicitToolCall");
|
|
4491
6644
|
async function runClaimedToolCall(turn, claimed) {
|
|
4492
6645
|
const { deps, input, hooks } = turn;
|
|
4493
6646
|
const { call, toolType, ctx } = claimed;
|
|
6647
|
+
if (claimed.proposalId !== void 0) {
|
|
6648
|
+
turn.halt.independentProposal = true;
|
|
6649
|
+
return {
|
|
6650
|
+
id: call.id,
|
|
6651
|
+
name: call.name,
|
|
6652
|
+
output: actionProposalReceipt(claimed.proposalId)
|
|
6653
|
+
};
|
|
6654
|
+
}
|
|
4494
6655
|
if (toolType === "agent") {
|
|
4495
6656
|
return delegateToolCall(turn, claimed);
|
|
4496
6657
|
}
|
|
4497
6658
|
if (toolType === "ask") {
|
|
4498
6659
|
return elicitToolCall(turn, claimed);
|
|
4499
6660
|
}
|
|
6661
|
+
if (claimed.preflight !== void 0 && claimed.preflight.status !== "ready") {
|
|
6662
|
+
const result2 = claimed.preflight;
|
|
6663
|
+
if (result2.status === "completed" && claimed.presentCompletedPreflight === true) {
|
|
6664
|
+
const raw = await hooks.step(`present:${call.id}`, async () => {
|
|
6665
|
+
const ui = createNegotiatedUiCollector(call.id, ctx, deps.resolveUiCatalog, (event) => turn.writer.write(encodeStreamEvent(event)));
|
|
6666
|
+
await deps.registry.presentOutput(call.name, result2.output, {
|
|
6667
|
+
...toolCallContext(ctx, call.id),
|
|
6668
|
+
emitUi: ui.emit
|
|
6669
|
+
});
|
|
6670
|
+
return wrapToolStepOutput(result2.output, ui.components(), ui.text());
|
|
6671
|
+
});
|
|
6672
|
+
const presented = unwrapToolStepOutput(raw);
|
|
6673
|
+
if (presented.ui.length > 0) turn.toolUi.set(call.id, presented.ui);
|
|
6674
|
+
if (presented.text) turn.toolText.set(call.id, presented.text);
|
|
6675
|
+
}
|
|
6676
|
+
if (result2.status === "completed" && claimed.terminal === true) turn.halt.terminal = true;
|
|
6677
|
+
const outcome = result2.status === "completed" ? {
|
|
6678
|
+
status: "executed",
|
|
6679
|
+
output: result2.output,
|
|
6680
|
+
executionMs: 0
|
|
6681
|
+
} : result2.status === "denied" ? {
|
|
6682
|
+
status: "denied",
|
|
6683
|
+
reason: result2.reason,
|
|
6684
|
+
executionMs: 0
|
|
6685
|
+
} : {
|
|
6686
|
+
status: "failed",
|
|
6687
|
+
error: result2.error,
|
|
6688
|
+
executionMs: 0
|
|
6689
|
+
};
|
|
6690
|
+
return recordToolOutcome(turn, claimed, outcome, input.actor.id);
|
|
6691
|
+
}
|
|
4500
6692
|
let deciderRef = input.actor.id;
|
|
4501
6693
|
let meta;
|
|
4502
6694
|
if (toolType === "action" && claimed.approval?.mode === "remembered") {
|
|
@@ -4621,30 +6813,30 @@ function expiryNarrative() {
|
|
|
4621
6813
|
return "This action needed approval, and the approval request expired before anyone decided. Nothing ran and nothing changed. Do not run it again on your own; tell the person it was not approved in time and ask whether they still want it.";
|
|
4622
6814
|
}
|
|
4623
6815
|
__name(expiryNarrative, "expiryNarrative");
|
|
4624
|
-
function outputFrame(
|
|
4625
|
-
if (
|
|
4626
|
-
const reason = refusalReason(
|
|
6816
|
+
function outputFrame(result2) {
|
|
6817
|
+
if (result2.denied === true) {
|
|
6818
|
+
const reason = refusalReason(result2);
|
|
4627
6819
|
return {
|
|
4628
6820
|
kind: "tool-output-denied",
|
|
4629
|
-
id:
|
|
6821
|
+
id: result2.id,
|
|
4630
6822
|
...reason !== void 0 ? {
|
|
4631
6823
|
reason
|
|
4632
6824
|
} : {}
|
|
4633
6825
|
};
|
|
4634
6826
|
}
|
|
4635
|
-
return
|
|
6827
|
+
return result2.error !== void 0 ? {
|
|
4636
6828
|
kind: "tool-output-error",
|
|
4637
|
-
id:
|
|
4638
|
-
error:
|
|
6829
|
+
id: result2.id,
|
|
6830
|
+
error: result2.error
|
|
4639
6831
|
} : {
|
|
4640
6832
|
kind: "tool-output",
|
|
4641
|
-
id:
|
|
4642
|
-
output:
|
|
6833
|
+
id: result2.id,
|
|
6834
|
+
output: result2.output
|
|
4643
6835
|
};
|
|
4644
6836
|
}
|
|
4645
6837
|
__name(outputFrame, "outputFrame");
|
|
4646
|
-
function refusalReason(
|
|
4647
|
-
const { output } =
|
|
6838
|
+
function refusalReason(result2) {
|
|
6839
|
+
const { output } = result2;
|
|
4648
6840
|
if (output !== null && typeof output === "object" && "reason" in output) {
|
|
4649
6841
|
const reason = output.reason;
|
|
4650
6842
|
return typeof reason === "string" && reason !== DEFAULT_REFUSAL_REASON ? reason : void 0;
|
|
@@ -4884,6 +7076,25 @@ ${block}`;
|
|
|
4884
7076
|
messages: prompt.messages,
|
|
4885
7077
|
actor: input.actor,
|
|
4886
7078
|
threadId: input.threadId,
|
|
7079
|
+
actionApprovalMode: history.actionApprovalMode ?? "blocking",
|
|
7080
|
+
preflightContext: {
|
|
7081
|
+
actor: input.actor,
|
|
7082
|
+
threadId: input.threadId,
|
|
7083
|
+
runId: hooks.runId,
|
|
7084
|
+
requestId: hooks.runId,
|
|
7085
|
+
...input.agentName !== void 0 ? {
|
|
7086
|
+
agentName: input.agentName
|
|
7087
|
+
} : {},
|
|
7088
|
+
...input.persona !== void 0 ? {
|
|
7089
|
+
persona: input.persona
|
|
7090
|
+
} : {},
|
|
7091
|
+
...input.pageContext !== void 0 ? {
|
|
7092
|
+
pageContext: input.pageContext
|
|
7093
|
+
} : {},
|
|
7094
|
+
...input.uiCapabilities !== void 0 ? {
|
|
7095
|
+
uiCapabilities: input.uiCapabilities
|
|
7096
|
+
} : {}
|
|
7097
|
+
},
|
|
4887
7098
|
...gated ? {
|
|
4888
7099
|
bufferOutput: true
|
|
4889
7100
|
} : {},
|
|
@@ -4900,6 +7111,9 @@ ${block}`;
|
|
|
4900
7111
|
tools: withAskTool({
|
|
4901
7112
|
tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, intersectAllowLists(deps.toolAllowList, persona?.allowedTools), {
|
|
4902
7113
|
threadId: input.threadId,
|
|
7114
|
+
...input.uiCapabilities !== void 0 ? {
|
|
7115
|
+
uiCapabilities: input.uiCapabilities
|
|
7116
|
+
} : {},
|
|
4903
7117
|
...input.agentName !== void 0 ? {
|
|
4904
7118
|
agentName: input.agentName
|
|
4905
7119
|
} : {}
|
|
@@ -4919,7 +7133,7 @@ ${block}`;
|
|
|
4919
7133
|
}) : void 0;
|
|
4920
7134
|
const buffer = gateMode === "whole" ? createFrameBuffer() : void 0;
|
|
4921
7135
|
const frames = observeTurnFrames(incremental?.writer ?? buffer?.writer ?? writer);
|
|
4922
|
-
const
|
|
7136
|
+
const result2 = stampToolKinds(withTurnFrames(await traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
|
|
4923
7137
|
system: prompt.system,
|
|
4924
7138
|
messages: prompt.messages,
|
|
4925
7139
|
tools,
|
|
@@ -4929,15 +7143,15 @@ ${block}`;
|
|
|
4929
7143
|
await incremental.settled();
|
|
4930
7144
|
const refusal = incremental.rejection();
|
|
4931
7145
|
return {
|
|
4932
|
-
...
|
|
7146
|
+
...result2,
|
|
4933
7147
|
releasedText: incremental.released(),
|
|
4934
7148
|
...refusal !== void 0 ? {
|
|
4935
7149
|
gateRejection: refusal
|
|
4936
7150
|
} : {}
|
|
4937
7151
|
};
|
|
4938
7152
|
}
|
|
4939
|
-
return buffer === void 0 ?
|
|
4940
|
-
...
|
|
7153
|
+
return buffer === void 0 ? result2 : {
|
|
7154
|
+
...result2,
|
|
4941
7155
|
bufferedFrames: buffer.frames()
|
|
4942
7156
|
};
|
|
4943
7157
|
});
|
|
@@ -5031,12 +7245,12 @@ ${block}`;
|
|
|
5031
7245
|
role: "assistant",
|
|
5032
7246
|
content: turn.text
|
|
5033
7247
|
}
|
|
5034
|
-
], count), (
|
|
5035
|
-
followUps:
|
|
5036
|
-
inputTokens:
|
|
5037
|
-
outputTokens:
|
|
5038
|
-
...
|
|
5039
|
-
modelId:
|
|
7248
|
+
], count), (result2) => ({
|
|
7249
|
+
followUps: result2.followUps.length,
|
|
7250
|
+
inputTokens: result2.usage.inputTokens,
|
|
7251
|
+
outputTokens: result2.usage.outputTokens,
|
|
7252
|
+
...result2.modelId !== void 0 ? {
|
|
7253
|
+
modelId: result2.modelId
|
|
5040
7254
|
} : {}
|
|
5041
7255
|
})));
|
|
5042
7256
|
let suggestions = generated.followUps;
|
|
@@ -5147,7 +7361,7 @@ ${block}`;
|
|
|
5147
7361
|
};
|
|
5148
7362
|
modelMessages.push(assistantMessage);
|
|
5149
7363
|
for (const entry of synthetic) {
|
|
5150
|
-
const { call, result } = entry;
|
|
7364
|
+
const { call, result: result2 } = entry;
|
|
5151
7365
|
await hooks.step(`${entry.step}:${assistant.id}`, async () => {
|
|
5152
7366
|
await deps.store.recordToolCall({
|
|
5153
7367
|
toolCallId: call.id,
|
|
@@ -5161,7 +7375,7 @@ ${block}`;
|
|
|
5161
7375
|
await deps.store.updateToolCall({
|
|
5162
7376
|
toolCallId: call.id,
|
|
5163
7377
|
status: "executed",
|
|
5164
|
-
output:
|
|
7378
|
+
output: result2.output
|
|
5165
7379
|
});
|
|
5166
7380
|
await writer.write(encodeStreamEvent({
|
|
5167
7381
|
kind: "tool-input-available",
|
|
@@ -5173,7 +7387,7 @@ ${block}`;
|
|
|
5173
7387
|
await writer.write(encodeStreamEvent({
|
|
5174
7388
|
kind: "tool-output",
|
|
5175
7389
|
id: call.id,
|
|
5176
|
-
output:
|
|
7390
|
+
output: result2.output
|
|
5177
7391
|
}));
|
|
5178
7392
|
});
|
|
5179
7393
|
}
|
|
@@ -5202,9 +7416,11 @@ ${block}`;
|
|
|
5202
7416
|
messageId: assistant.id,
|
|
5203
7417
|
writer,
|
|
5204
7418
|
toolUi: /* @__PURE__ */ new Map(),
|
|
7419
|
+
toolText: /* @__PURE__ */ new Map(),
|
|
5205
7420
|
halt: {
|
|
5206
7421
|
terminal: false
|
|
5207
7422
|
},
|
|
7423
|
+
actionApprovalMode: history.actionApprovalMode ?? "blocking",
|
|
5208
7424
|
...skillOffer !== void 0 ? {
|
|
5209
7425
|
skills: skillOffer
|
|
5210
7426
|
} : {},
|
|
@@ -5237,17 +7453,35 @@ ${block}`;
|
|
|
5237
7453
|
...results,
|
|
5238
7454
|
...syntheticResults
|
|
5239
7455
|
];
|
|
7456
|
+
const toolText = escapeUnsafeToolUiText(toolCallsWithKind.map((call) => turnCalls.toolText.get(call.id)).filter((text) => text !== void 0).join("\n"));
|
|
5240
7457
|
assistantMessage.toolResults = settledResults;
|
|
5241
7458
|
await hooks.step(`stream:tool-outputs:${i}`, async () => {
|
|
5242
7459
|
await deps.store.setMessageToolResults(assistant.id, settledResults);
|
|
7460
|
+
if (toolText) await deps.store.appendMessage({
|
|
7461
|
+
threadId: input.threadId,
|
|
7462
|
+
role: "assistant",
|
|
7463
|
+
content: toolText,
|
|
7464
|
+
runId: hooks.runId,
|
|
7465
|
+
...input.agentName !== void 0 ? {
|
|
7466
|
+
agentName: input.agentName
|
|
7467
|
+
} : {}
|
|
7468
|
+
});
|
|
5243
7469
|
const toolUi = toolCallsWithKind.flatMap((call) => turnCalls.toolUi.get(call.id) ?? []);
|
|
5244
7470
|
if (toolUi.length > 0) {
|
|
5245
7471
|
await deps.store.setMessageUi?.(assistant.id, mergeUi(turn.ui, toolUi));
|
|
5246
7472
|
}
|
|
5247
|
-
for (const
|
|
5248
|
-
await writer.write(encodeStreamEvent(outputFrame(
|
|
7473
|
+
for (const result2 of results) {
|
|
7474
|
+
await writer.write(encodeStreamEvent(outputFrame(result2)));
|
|
5249
7475
|
}
|
|
5250
7476
|
});
|
|
7477
|
+
if (toolText) {
|
|
7478
|
+
modelMessages.push({
|
|
7479
|
+
role: "assistant",
|
|
7480
|
+
content: toolText
|
|
7481
|
+
});
|
|
7482
|
+
lastText += `
|
|
7483
|
+
${toolText}`;
|
|
7484
|
+
}
|
|
5251
7485
|
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
5252
7486
|
await writer.write(encodeStreamEvent({
|
|
5253
7487
|
kind: "step-finish",
|
|
@@ -5261,7 +7495,7 @@ ${block}`;
|
|
|
5261
7495
|
} : {}
|
|
5262
7496
|
}));
|
|
5263
7497
|
});
|
|
5264
|
-
if (turnCalls.halt.terminal) {
|
|
7498
|
+
if (turnCalls.halt.terminal || turnCalls.halt.independentProposal) {
|
|
5265
7499
|
break;
|
|
5266
7500
|
}
|
|
5267
7501
|
}
|
|
@@ -5317,8 +7551,152 @@ ${block}`;
|
|
|
5317
7551
|
}
|
|
5318
7552
|
__name(runAgentLoop, "runAgentLoop");
|
|
5319
7553
|
|
|
7554
|
+
// src/in-memory-action-proposal-store.ts
|
|
7555
|
+
var import_node_crypto2 = require("crypto");
|
|
7556
|
+
var InMemoryActionProposalStore = class {
|
|
7557
|
+
static {
|
|
7558
|
+
__name(this, "InMemoryActionProposalStore");
|
|
7559
|
+
}
|
|
7560
|
+
rows = /* @__PURE__ */ new Map();
|
|
7561
|
+
clock;
|
|
7562
|
+
constructor(options = {}) {
|
|
7563
|
+
this.clock = options.clock ?? Date.now;
|
|
7564
|
+
}
|
|
7565
|
+
async createActionProposal(input) {
|
|
7566
|
+
validateActionProposalCreation(input);
|
|
7567
|
+
const row2 = this.rows.get(input.id);
|
|
7568
|
+
if (row2) {
|
|
7569
|
+
if (!actionProposalScopeMatches(row2, input)) return {
|
|
7570
|
+
status: "conflict"
|
|
7571
|
+
};
|
|
7572
|
+
return {
|
|
7573
|
+
status: actionProposalCreationMatches(row2, input) ? "unchanged" : "conflict",
|
|
7574
|
+
proposal: snapshotActionProposal(row2)
|
|
7575
|
+
};
|
|
7576
|
+
}
|
|
7577
|
+
const proposal = initialActionProposal(input, this.clock());
|
|
7578
|
+
this.rows.set(input.id, proposal);
|
|
7579
|
+
return {
|
|
7580
|
+
status: "created",
|
|
7581
|
+
proposal: snapshotActionProposal(proposal)
|
|
7582
|
+
};
|
|
7583
|
+
}
|
|
7584
|
+
async getActionProposal(scope, id) {
|
|
7585
|
+
const row2 = this.rows.get(id);
|
|
7586
|
+
return row2 && actionProposalScopeMatches(row2, scope) ? snapshotActionProposal(row2) : null;
|
|
7587
|
+
}
|
|
7588
|
+
async listActionProposals(scope, query = {}) {
|
|
7589
|
+
const limit = validateActionProposalListQuery(query);
|
|
7590
|
+
return [
|
|
7591
|
+
...this.rows.values()
|
|
7592
|
+
].filter((row2) => actionProposalScopeMatches(row2, scope) && (query.decision === void 0 || row2.decision === query.decision) && (query.after === void 0 || row2.createdAt > query.after.createdAt || row2.createdAt === query.after.createdAt && row2.id > query.after.id)).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, limit).map(snapshotActionProposal);
|
|
7593
|
+
}
|
|
7594
|
+
mutate(scope, id, transition) {
|
|
7595
|
+
const row2 = this.rows.get(id);
|
|
7596
|
+
if (!row2 || !actionProposalScopeMatches(row2, scope)) return {
|
|
7597
|
+
status: "not_found"
|
|
7598
|
+
};
|
|
7599
|
+
const result2 = transition(row2, this.clock());
|
|
7600
|
+
if (result2.proposal) this.rows.set(id, snapshotActionProposal(result2.proposal));
|
|
7601
|
+
return result2;
|
|
7602
|
+
}
|
|
7603
|
+
async decideActionProposal(scope, id, command) {
|
|
7604
|
+
return this.mutate(scope, id, (row2, now) => transitionActionProposalDecision(row2, command, now));
|
|
7605
|
+
}
|
|
7606
|
+
async claimActionProposal(scope, id, command) {
|
|
7607
|
+
return this.mutate(scope, id, (row2, now) => transitionActionProposalClaim(row2, command, now, (0, import_node_crypto2.randomUUID)()));
|
|
7608
|
+
}
|
|
7609
|
+
async extendActionProposalLease(scope, id, command) {
|
|
7610
|
+
return this.mutate(scope, id, (row2, now) => transitionActionProposalLease(row2, command, now));
|
|
7611
|
+
}
|
|
7612
|
+
async settleActionProposal(scope, id, command) {
|
|
7613
|
+
return this.mutate(scope, id, (row2, now) => transitionActionProposalSettlement(row2, command, now));
|
|
7614
|
+
}
|
|
7615
|
+
async claimNextActionProposal(command) {
|
|
7616
|
+
const now = this.clock();
|
|
7617
|
+
validateActionProposalWorkerClaim(command, now);
|
|
7618
|
+
const candidates = [
|
|
7619
|
+
...this.rows.values()
|
|
7620
|
+
].filter((row2) => row2.decision === "approved" && (row2.execution?.status === "queued" || row2.execution?.status === "executing" && row2.execution.lease !== null && now >= row2.execution.lease.expiresAt)).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, 32);
|
|
7621
|
+
for (const candidate of candidates) {
|
|
7622
|
+
const claimed = await this.claimActionProposal(candidate, candidate.id, command);
|
|
7623
|
+
if (claimed.status === "applied" && claimed.proposal) return claimed.proposal;
|
|
7624
|
+
}
|
|
7625
|
+
return null;
|
|
7626
|
+
}
|
|
7627
|
+
async expireActionProposals(command) {
|
|
7628
|
+
const now = this.clock();
|
|
7629
|
+
validateActionProposalExpiryBatch(command, now);
|
|
7630
|
+
const candidates = [
|
|
7631
|
+
...this.rows.values()
|
|
7632
|
+
].filter((row2) => row2.decision === "pending" && row2.expiresAt !== null && now >= row2.expiresAt).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, command.limit);
|
|
7633
|
+
let expired = 0;
|
|
7634
|
+
for (const candidate of candidates) {
|
|
7635
|
+
const result2 = await this.decideActionProposal(candidate, candidate.id, {
|
|
7636
|
+
decision: "expired",
|
|
7637
|
+
actorRef: "system",
|
|
7638
|
+
via: "expiry"
|
|
7639
|
+
});
|
|
7640
|
+
if (result2.status === "applied") expired++;
|
|
7641
|
+
}
|
|
7642
|
+
return expired;
|
|
7643
|
+
}
|
|
7644
|
+
async claimNextActionProposalOutcome(command) {
|
|
7645
|
+
const now = this.clock();
|
|
7646
|
+
validateActionProposalWorkerClaim(command, now);
|
|
7647
|
+
const candidates = [
|
|
7648
|
+
...this.rows.values()
|
|
7649
|
+
].filter((row2) => row2.outcomeDelivery?.status === "pending" && (!row2.outcomeDelivery.lease || now >= row2.outcomeDelivery.lease.expiresAt)).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, 32);
|
|
7650
|
+
for (const candidate of candidates) {
|
|
7651
|
+
const row2 = this.rows.get(candidate.id);
|
|
7652
|
+
if (!row2) continue;
|
|
7653
|
+
const next = claimActionProposalOutcome(row2, command, this.clock(), (0, import_node_crypto2.randomUUID)());
|
|
7654
|
+
if (!next?.outcome || !next.outcomeDelivery?.lease) continue;
|
|
7655
|
+
this.rows.set(next.id, next);
|
|
7656
|
+
return {
|
|
7657
|
+
outcome: snapshotActionProposal(next.outcome),
|
|
7658
|
+
lease: {
|
|
7659
|
+
outcomeId: next.outcome.id,
|
|
7660
|
+
token: next.outcomeDelivery.lease.token,
|
|
7661
|
+
generation: next.outcomeDelivery.generation
|
|
7662
|
+
}
|
|
7663
|
+
};
|
|
7664
|
+
}
|
|
7665
|
+
return null;
|
|
7666
|
+
}
|
|
7667
|
+
async createReplacingActionProposal(input) {
|
|
7668
|
+
validateActionProposalCreation(input);
|
|
7669
|
+
const existing = this.rows.get(input.id);
|
|
7670
|
+
if (existing) return this.createActionProposal(input);
|
|
7671
|
+
const proposal = initialActionProposal(input, this.clock());
|
|
7672
|
+
const replacements = [];
|
|
7673
|
+
if (input.replacementKey) for (const row2 of this.rows.values()) {
|
|
7674
|
+
if (row2.decision !== "pending" || !actionProposalScopeMatches(row2, input) || row2.toolName !== input.toolName || row2.replacementKey !== input.replacementKey) continue;
|
|
7675
|
+
const result2 = transitionActionProposalSupersession(row2, proposal, {
|
|
7676
|
+
replacementProposalId: proposal.id,
|
|
7677
|
+
actorRef: input.actorRef,
|
|
7678
|
+
via: "supersession"
|
|
7679
|
+
}, this.clock());
|
|
7680
|
+
if (result2.proposal) replacements.push(result2.proposal);
|
|
7681
|
+
}
|
|
7682
|
+
this.rows.set(proposal.id, proposal);
|
|
7683
|
+
for (const row2 of replacements) this.rows.set(row2.id, row2);
|
|
7684
|
+
return {
|
|
7685
|
+
status: "created",
|
|
7686
|
+
proposal: snapshotActionProposal(proposal)
|
|
7687
|
+
};
|
|
7688
|
+
}
|
|
7689
|
+
async supersedeActionProposal(scope, id, command) {
|
|
7690
|
+
const replacement = this.rows.get(command.replacementProposalId);
|
|
7691
|
+
if (!replacement || !actionProposalScopeMatches(replacement, scope)) return {
|
|
7692
|
+
status: "not_found"
|
|
7693
|
+
};
|
|
7694
|
+
return this.mutate(scope, id, (row2, now) => transitionActionProposalSupersession(row2, replacement, command, now));
|
|
7695
|
+
}
|
|
7696
|
+
};
|
|
7697
|
+
|
|
5320
7698
|
// src/in-memory-store.ts
|
|
5321
|
-
var InMemoryAgentStore = class {
|
|
7699
|
+
var InMemoryAgentStore = class extends InMemoryActionProposalStore {
|
|
5322
7700
|
static {
|
|
5323
7701
|
__name(this, "InMemoryAgentStore");
|
|
5324
7702
|
}
|
|
@@ -5338,9 +7716,10 @@ var InMemoryAgentStore = class {
|
|
|
5338
7716
|
throw new Error(`thread ${id} already exists`);
|
|
5339
7717
|
}
|
|
5340
7718
|
const ts = this.now();
|
|
5341
|
-
const
|
|
7719
|
+
const row2 = {
|
|
5342
7720
|
id,
|
|
5343
7721
|
actorRef: input.actor.id,
|
|
7722
|
+
tenantRef: input.actor.tenantRef ?? null,
|
|
5344
7723
|
title: input.title ?? "New chat",
|
|
5345
7724
|
transient: input.transient ?? false,
|
|
5346
7725
|
createdAt: ts,
|
|
@@ -5350,20 +7729,20 @@ var InMemoryAgentStore = class {
|
|
|
5350
7729
|
persona: input.persona
|
|
5351
7730
|
} : {}
|
|
5352
7731
|
};
|
|
5353
|
-
this.threads.set(id,
|
|
5354
|
-
return this.toSummary(
|
|
7732
|
+
this.threads.set(id, row2);
|
|
7733
|
+
return this.toSummary(row2);
|
|
5355
7734
|
}
|
|
5356
7735
|
async getThread(threadId) {
|
|
5357
|
-
const
|
|
5358
|
-
if (
|
|
7736
|
+
const row2 = this.threads.get(threadId);
|
|
7737
|
+
if (row2 === void 0) {
|
|
5359
7738
|
return null;
|
|
5360
7739
|
}
|
|
5361
7740
|
return {
|
|
5362
|
-
...this.toSummary(
|
|
5363
|
-
messages:
|
|
7741
|
+
...this.toSummary(row2),
|
|
7742
|
+
messages: row2.messages.map((message) => this.withApprovals(message)),
|
|
5364
7743
|
// The run streaming right now — the one field the read-model reports it under.
|
|
5365
|
-
...
|
|
5366
|
-
activeRunId:
|
|
7744
|
+
...row2.activeStreamId !== void 0 ? {
|
|
7745
|
+
activeRunId: row2.activeStreamId
|
|
5367
7746
|
} : {}
|
|
5368
7747
|
};
|
|
5369
7748
|
}
|
|
@@ -5376,8 +7755,12 @@ var InMemoryAgentStore = class {
|
|
|
5376
7755
|
}
|
|
5377
7756
|
const approval = toolCallApprovalFromRow({
|
|
5378
7757
|
toolCallId: call.toolCallId,
|
|
7758
|
+
...call.proposalId !== void 0 ? {
|
|
7759
|
+
proposalId: call.proposalId
|
|
7760
|
+
} : {},
|
|
5379
7761
|
status: call.status,
|
|
5380
7762
|
approver: call.approver,
|
|
7763
|
+
confirmation: call.confirmation,
|
|
5381
7764
|
expiresAt: call.expiresAt,
|
|
5382
7765
|
remember: call.remember,
|
|
5383
7766
|
executedByRef: call.executedByRef,
|
|
@@ -5400,6 +7783,10 @@ var InMemoryAgentStore = class {
|
|
|
5400
7783
|
names.add(call.toolName);
|
|
5401
7784
|
}
|
|
5402
7785
|
}
|
|
7786
|
+
const thread = this.threads.get(threadId);
|
|
7787
|
+
if (thread) {
|
|
7788
|
+
for (const proposal of this.rows.values()) if (proposal.threadId === threadId && proposal.actorRef === thread.actorRef && proposal.tenantRef === thread.tenantRef && proposal.decisionAudit?.remember === true && (proposal.execution?.status === "succeeded" || proposal.execution?.status === "failed")) names.add(proposal.toolName);
|
|
7789
|
+
}
|
|
5403
7790
|
return [
|
|
5404
7791
|
...names
|
|
5405
7792
|
];
|
|
@@ -5421,7 +7808,7 @@ var InMemoryAgentStore = class {
|
|
|
5421
7808
|
async listThreads(actorRef, limit = 50) {
|
|
5422
7809
|
return [
|
|
5423
7810
|
...this.threads.values()
|
|
5424
|
-
].filter((
|
|
7811
|
+
].filter((row2) => row2.actorRef === actorRef && !row2.transient).sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)).slice(0, limit).map((row2) => this.toSummary(row2));
|
|
5425
7812
|
}
|
|
5426
7813
|
async softDeleteThread(threadId) {
|
|
5427
7814
|
this.threads.delete(threadId);
|
|
@@ -5437,9 +7824,10 @@ var InMemoryAgentStore = class {
|
|
|
5437
7824
|
];
|
|
5438
7825
|
const id = crypto.randomUUID();
|
|
5439
7826
|
const ts = this.now();
|
|
5440
|
-
const
|
|
7827
|
+
const row2 = {
|
|
5441
7828
|
id,
|
|
5442
7829
|
actorRef: source.actorRef,
|
|
7830
|
+
tenantRef: source.tenantRef,
|
|
5443
7831
|
title: source.title,
|
|
5444
7832
|
transient: false,
|
|
5445
7833
|
createdAt: ts,
|
|
@@ -5458,8 +7846,8 @@ var InMemoryAgentStore = class {
|
|
|
5458
7846
|
persona: source.persona
|
|
5459
7847
|
} : {}
|
|
5460
7848
|
};
|
|
5461
|
-
this.threads.set(id,
|
|
5462
|
-
return this.toSummary(
|
|
7849
|
+
this.threads.set(id, row2);
|
|
7850
|
+
return this.toSummary(row2);
|
|
5463
7851
|
}
|
|
5464
7852
|
async ownerOfThread(threadId) {
|
|
5465
7853
|
return this.threads.get(threadId)?.actorRef ?? null;
|
|
@@ -5479,38 +7867,38 @@ var InMemoryAgentStore = class {
|
|
|
5479
7867
|
return call.runId ?? this.threads.get(call.threadId)?.activeStreamId ?? null;
|
|
5480
7868
|
}
|
|
5481
7869
|
async ownerOfActiveStream(runId) {
|
|
5482
|
-
for (const
|
|
5483
|
-
if (
|
|
5484
|
-
return
|
|
7870
|
+
for (const row2 of this.threads.values()) {
|
|
7871
|
+
if (row2.activeStreamId === runId) {
|
|
7872
|
+
return row2.actorRef;
|
|
5485
7873
|
}
|
|
5486
7874
|
}
|
|
5487
7875
|
return null;
|
|
5488
7876
|
}
|
|
5489
7877
|
async setTitle(threadId, title) {
|
|
5490
|
-
const
|
|
5491
|
-
if (
|
|
5492
|
-
|
|
5493
|
-
|
|
7878
|
+
const row2 = this.threads.get(threadId);
|
|
7879
|
+
if (row2 !== void 0) {
|
|
7880
|
+
row2.title = title;
|
|
7881
|
+
row2.updatedAt = this.now();
|
|
5494
7882
|
}
|
|
5495
7883
|
}
|
|
5496
7884
|
async updateThread(threadId, patch) {
|
|
5497
|
-
const
|
|
5498
|
-
if (
|
|
7885
|
+
const row2 = this.threads.get(threadId);
|
|
7886
|
+
if (row2 === void 0) {
|
|
5499
7887
|
return;
|
|
5500
7888
|
}
|
|
5501
7889
|
if (patch.title !== void 0) {
|
|
5502
|
-
|
|
7890
|
+
row2.title = patch.title;
|
|
5503
7891
|
}
|
|
5504
7892
|
if (patch.defaultAgent !== void 0) {
|
|
5505
|
-
|
|
7893
|
+
row2.defaultAgent = patch.defaultAgent;
|
|
5506
7894
|
}
|
|
5507
7895
|
if (patch.model !== void 0) {
|
|
5508
|
-
|
|
7896
|
+
row2.model = patch.model;
|
|
5509
7897
|
}
|
|
5510
7898
|
if (patch.persona !== void 0) {
|
|
5511
|
-
|
|
7899
|
+
row2.persona = patch.persona;
|
|
5512
7900
|
}
|
|
5513
|
-
|
|
7901
|
+
row2.updatedAt = this.now();
|
|
5514
7902
|
}
|
|
5515
7903
|
async activeRunForThread(threadId) {
|
|
5516
7904
|
return this.threads.get(threadId)?.activeStreamId ?? null;
|
|
@@ -5558,64 +7946,64 @@ var InMemoryAgentStore = class {
|
|
|
5558
7946
|
}
|
|
5559
7947
|
/** Settle a run's outcome. A no-op when the run is unknown (mirrors `setTitle`/`updateThread`). */
|
|
5560
7948
|
async recordRunEnd(end) {
|
|
5561
|
-
const
|
|
5562
|
-
if (
|
|
7949
|
+
const row2 = this.runs.get(end.runId);
|
|
7950
|
+
if (row2 === void 0) {
|
|
5563
7951
|
return;
|
|
5564
7952
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
7953
|
+
row2.status = end.status;
|
|
7954
|
+
row2.settledAt = this.now();
|
|
5567
7955
|
if (end.durationMs !== void 0) {
|
|
5568
|
-
|
|
7956
|
+
row2.durationMs = end.durationMs;
|
|
5569
7957
|
}
|
|
5570
7958
|
if (end.errorCode !== void 0) {
|
|
5571
|
-
|
|
7959
|
+
row2.errorCode = end.errorCode;
|
|
5572
7960
|
}
|
|
5573
7961
|
if (end.errorMessage !== void 0) {
|
|
5574
|
-
|
|
7962
|
+
row2.errorMessage = end.errorMessage;
|
|
5575
7963
|
}
|
|
5576
7964
|
}
|
|
5577
7965
|
/** Bump the run's llm-step retry counter. */
|
|
5578
7966
|
async bumpRunRetries(runId) {
|
|
5579
|
-
const
|
|
5580
|
-
if (
|
|
5581
|
-
|
|
7967
|
+
const row2 = this.runs.get(runId);
|
|
7968
|
+
if (row2 !== void 0) {
|
|
7969
|
+
row2.retries += 1;
|
|
5582
7970
|
}
|
|
5583
7971
|
}
|
|
5584
7972
|
async promoteThread(threadId) {
|
|
5585
|
-
const
|
|
5586
|
-
if (
|
|
5587
|
-
|
|
5588
|
-
|
|
7973
|
+
const row2 = this.threads.get(threadId);
|
|
7974
|
+
if (row2?.transient) {
|
|
7975
|
+
row2.transient = false;
|
|
7976
|
+
row2.updatedAt = this.now();
|
|
5589
7977
|
}
|
|
5590
7978
|
}
|
|
5591
7979
|
async setActiveStream(threadId, runId) {
|
|
5592
|
-
const
|
|
5593
|
-
if (
|
|
7980
|
+
const row2 = this.threads.get(threadId);
|
|
7981
|
+
if (row2 !== void 0) {
|
|
5594
7982
|
if (runId === null) {
|
|
5595
|
-
delete
|
|
7983
|
+
delete row2.activeStreamId;
|
|
5596
7984
|
} else {
|
|
5597
|
-
|
|
7985
|
+
row2.activeStreamId = runId;
|
|
5598
7986
|
}
|
|
5599
7987
|
}
|
|
5600
7988
|
}
|
|
5601
7989
|
async claimActiveStream(threadId, runId, options = {}) {
|
|
5602
|
-
const
|
|
5603
|
-
if (
|
|
7990
|
+
const row2 = this.threads.get(threadId);
|
|
7991
|
+
if (row2 === void 0) {
|
|
5604
7992
|
return false;
|
|
5605
7993
|
}
|
|
5606
|
-
const holder =
|
|
7994
|
+
const holder = row2.activeStreamId;
|
|
5607
7995
|
if (holder !== void 0 && holder !== runId && holder !== options.replacing) {
|
|
5608
7996
|
return false;
|
|
5609
7997
|
}
|
|
5610
|
-
|
|
7998
|
+
row2.activeStreamId = runId;
|
|
5611
7999
|
return true;
|
|
5612
8000
|
}
|
|
5613
8001
|
async releaseActiveStream(threadId, runId) {
|
|
5614
|
-
const
|
|
5615
|
-
if (
|
|
8002
|
+
const row2 = this.threads.get(threadId);
|
|
8003
|
+
if (row2?.activeStreamId !== runId) {
|
|
5616
8004
|
return false;
|
|
5617
8005
|
}
|
|
5618
|
-
delete
|
|
8006
|
+
delete row2.activeStreamId;
|
|
5619
8007
|
return true;
|
|
5620
8008
|
}
|
|
5621
8009
|
async enqueueMessage(input) {
|
|
@@ -5640,6 +8028,9 @@ var InMemoryAgentStore = class {
|
|
|
5640
8028
|
...input.pageContext !== void 0 ? {
|
|
5641
8029
|
pageContext: input.pageContext
|
|
5642
8030
|
} : {},
|
|
8031
|
+
...input.uiCapabilities !== void 0 ? {
|
|
8032
|
+
uiCapabilities: input.uiCapabilities
|
|
8033
|
+
} : {},
|
|
5643
8034
|
...input.interrupt === true ? {
|
|
5644
8035
|
interrupt: true
|
|
5645
8036
|
} : {},
|
|
@@ -5744,9 +8135,81 @@ var InMemoryAgentStore = class {
|
|
|
5744
8135
|
}
|
|
5745
8136
|
return void 0;
|
|
5746
8137
|
}
|
|
8138
|
+
async getThreadActionProposalScope(threadId) {
|
|
8139
|
+
const row2 = this.threads.get(threadId);
|
|
8140
|
+
return row2 ? {
|
|
8141
|
+
threadId,
|
|
8142
|
+
actorRef: row2.actorRef,
|
|
8143
|
+
tenantRef: row2.tenantRef
|
|
8144
|
+
} : null;
|
|
8145
|
+
}
|
|
8146
|
+
async admitActionProposalOutcome(command) {
|
|
8147
|
+
const row2 = [
|
|
8148
|
+
...this.rows.values()
|
|
8149
|
+
].find((row3) => row3.outcome?.id === command.outcomeId);
|
|
8150
|
+
if (!row2?.outcome || !row2.outcomeDelivery) return {
|
|
8151
|
+
status: "not_found"
|
|
8152
|
+
};
|
|
8153
|
+
if (row2.outcomeDelivery.status === "admitted") return {
|
|
8154
|
+
status: "unchanged",
|
|
8155
|
+
...row2.outcomeDelivery.messageId !== void 0 ? {
|
|
8156
|
+
messageId: row2.outcomeDelivery.messageId
|
|
8157
|
+
} : {}
|
|
8158
|
+
};
|
|
8159
|
+
if (row2.outcomeDelivery.status === "discarded") return {
|
|
8160
|
+
status: "discarded"
|
|
8161
|
+
};
|
|
8162
|
+
if (!actionProposalOutcomeFenceValid(row2, command, this.clock())) return {
|
|
8163
|
+
status: "conflict"
|
|
8164
|
+
};
|
|
8165
|
+
const thread = this.threads.get(row2.threadId);
|
|
8166
|
+
if (!thread) {
|
|
8167
|
+
this.rows.set(row2.id, snapshotActionProposal({
|
|
8168
|
+
...row2,
|
|
8169
|
+
outcomeDelivery: {
|
|
8170
|
+
...row2.outcomeDelivery,
|
|
8171
|
+
status: "discarded",
|
|
8172
|
+
lease: null
|
|
8173
|
+
}
|
|
8174
|
+
}));
|
|
8175
|
+
return {
|
|
8176
|
+
status: "discarded"
|
|
8177
|
+
};
|
|
8178
|
+
}
|
|
8179
|
+
if (thread.actorRef !== row2.actorRef || thread.tenantRef !== row2.tenantRef) return {
|
|
8180
|
+
status: "conflict"
|
|
8181
|
+
};
|
|
8182
|
+
if (thread.activeStreamId) return {
|
|
8183
|
+
status: "busy"
|
|
8184
|
+
};
|
|
8185
|
+
const message = {
|
|
8186
|
+
id: crypto.randomUUID(),
|
|
8187
|
+
role: "assistant",
|
|
8188
|
+
content: actionProposalOutcomeText(row2.outcome),
|
|
8189
|
+
createdAt: this.now(),
|
|
8190
|
+
actionProposalOutcome: snapshotActionProposal(row2.outcome),
|
|
8191
|
+
ui: snapshotActionProposal(row2.outcome.ui)
|
|
8192
|
+
};
|
|
8193
|
+
const next = snapshotActionProposal({
|
|
8194
|
+
...row2,
|
|
8195
|
+
outcomeDelivery: {
|
|
8196
|
+
...row2.outcomeDelivery,
|
|
8197
|
+
status: "admitted",
|
|
8198
|
+
lease: null,
|
|
8199
|
+
messageId: message.id
|
|
8200
|
+
}
|
|
8201
|
+
});
|
|
8202
|
+
thread.messages.push(message);
|
|
8203
|
+
thread.updatedAt = message.createdAt;
|
|
8204
|
+
this.rows.set(row2.id, next);
|
|
8205
|
+
return {
|
|
8206
|
+
status: "applied",
|
|
8207
|
+
messageId: message.id
|
|
8208
|
+
};
|
|
8209
|
+
}
|
|
5747
8210
|
async appendMessage(input) {
|
|
5748
|
-
const
|
|
5749
|
-
if (
|
|
8211
|
+
const row2 = this.threads.get(input.threadId);
|
|
8212
|
+
if (row2 === void 0) {
|
|
5750
8213
|
throw new Error(`thread ${input.threadId} not found`);
|
|
5751
8214
|
}
|
|
5752
8215
|
const message = {
|
|
@@ -5786,15 +8249,18 @@ var InMemoryAgentStore = class {
|
|
|
5786
8249
|
} : {},
|
|
5787
8250
|
...input.ui !== void 0 ? {
|
|
5788
8251
|
ui: input.ui
|
|
8252
|
+
} : {},
|
|
8253
|
+
...input.actionProposalOutcome !== void 0 ? {
|
|
8254
|
+
actionProposalOutcome: input.actionProposalOutcome
|
|
5789
8255
|
} : {}
|
|
5790
8256
|
};
|
|
5791
|
-
|
|
5792
|
-
|
|
8257
|
+
row2.messages.push(message);
|
|
8258
|
+
row2.updatedAt = message.createdAt;
|
|
5793
8259
|
return message;
|
|
5794
8260
|
}
|
|
5795
8261
|
async setMessageToolResults(messageId, results) {
|
|
5796
|
-
for (const
|
|
5797
|
-
const message =
|
|
8262
|
+
for (const row2 of this.threads.values()) {
|
|
8263
|
+
const message = row2.messages.find((candidate) => candidate.id === messageId);
|
|
5798
8264
|
if (message !== void 0) {
|
|
5799
8265
|
message.toolResults = results;
|
|
5800
8266
|
return;
|
|
@@ -5802,12 +8268,12 @@ var InMemoryAgentStore = class {
|
|
|
5802
8268
|
}
|
|
5803
8269
|
}
|
|
5804
8270
|
async setMessageUi(messageId, ui) {
|
|
5805
|
-
for (const
|
|
5806
|
-
const index =
|
|
5807
|
-
const message =
|
|
8271
|
+
for (const row2 of this.threads.values()) {
|
|
8272
|
+
const index = row2.messages.findIndex((candidate) => candidate.id === messageId);
|
|
8273
|
+
const message = row2.messages[index];
|
|
5808
8274
|
if (message !== void 0) {
|
|
5809
8275
|
const { ui: _previous, ...rest } = message;
|
|
5810
|
-
|
|
8276
|
+
row2.messages[index] = ui.length > 0 ? {
|
|
5811
8277
|
...rest,
|
|
5812
8278
|
ui
|
|
5813
8279
|
} : rest;
|
|
@@ -5819,12 +8285,12 @@ var InMemoryAgentStore = class {
|
|
|
5819
8285
|
return this.threadIdForMessage(messageId) ?? null;
|
|
5820
8286
|
}
|
|
5821
8287
|
async setMessageFeedback(messageId, feedback) {
|
|
5822
|
-
for (const
|
|
5823
|
-
const index =
|
|
5824
|
-
const message =
|
|
8288
|
+
for (const row2 of this.threads.values()) {
|
|
8289
|
+
const index = row2.messages.findIndex((candidate) => candidate.id === messageId);
|
|
8290
|
+
const message = row2.messages[index];
|
|
5825
8291
|
if (message !== void 0) {
|
|
5826
8292
|
const { feedback: _previous, ...rest } = message;
|
|
5827
|
-
|
|
8293
|
+
row2.messages[index] = feedback !== null ? {
|
|
5828
8294
|
...rest,
|
|
5829
8295
|
feedback
|
|
5830
8296
|
} : rest;
|
|
@@ -5833,13 +8299,13 @@ var InMemoryAgentStore = class {
|
|
|
5833
8299
|
}
|
|
5834
8300
|
}
|
|
5835
8301
|
async truncateFrom(threadId, messageId) {
|
|
5836
|
-
const
|
|
5837
|
-
if (
|
|
8302
|
+
const row2 = this.threads.get(threadId);
|
|
8303
|
+
if (row2 === void 0) {
|
|
5838
8304
|
return;
|
|
5839
8305
|
}
|
|
5840
|
-
const cutoff =
|
|
8306
|
+
const cutoff = row2.messages.findIndex((message) => message.id === messageId);
|
|
5841
8307
|
if (cutoff >= 0) {
|
|
5842
|
-
|
|
8308
|
+
row2.messages = row2.messages.slice(0, cutoff);
|
|
5843
8309
|
}
|
|
5844
8310
|
}
|
|
5845
8311
|
/**
|
|
@@ -5877,6 +8343,9 @@ var InMemoryAgentStore = class {
|
|
|
5877
8343
|
async recordToolCall(input) {
|
|
5878
8344
|
this.toolCalls.set(input.toolCallId, {
|
|
5879
8345
|
toolCallId: input.toolCallId,
|
|
8346
|
+
...input.proposalId !== void 0 ? {
|
|
8347
|
+
proposalId: input.proposalId
|
|
8348
|
+
} : {},
|
|
5880
8349
|
messageId: input.messageId,
|
|
5881
8350
|
threadId: this.threadIdForMessage(input.messageId) ?? "",
|
|
5882
8351
|
toolName: input.toolName,
|
|
@@ -5890,6 +8359,9 @@ var InMemoryAgentStore = class {
|
|
|
5890
8359
|
...input.approver !== void 0 ? {
|
|
5891
8360
|
approver: input.approver
|
|
5892
8361
|
} : {},
|
|
8362
|
+
...input.confirmation !== void 0 ? {
|
|
8363
|
+
confirmation: structuredClone(input.confirmation)
|
|
8364
|
+
} : {},
|
|
5893
8365
|
...input.expiresAt !== void 0 ? {
|
|
5894
8366
|
expiresAt: input.expiresAt
|
|
5895
8367
|
} : {}
|
|
@@ -5898,16 +8370,16 @@ var InMemoryAgentStore = class {
|
|
|
5898
8370
|
async toolCallOutcomes(toolCallIds) {
|
|
5899
8371
|
const outcomes = [];
|
|
5900
8372
|
for (const id of toolCallIds) {
|
|
5901
|
-
const
|
|
5902
|
-
if (
|
|
8373
|
+
const row2 = this.toolCalls.get(id);
|
|
8374
|
+
if (row2 !== void 0) {
|
|
5903
8375
|
outcomes.push({
|
|
5904
8376
|
id,
|
|
5905
|
-
status:
|
|
5906
|
-
...
|
|
5907
|
-
output:
|
|
8377
|
+
status: row2.status,
|
|
8378
|
+
...row2.output !== void 0 ? {
|
|
8379
|
+
output: row2.output
|
|
5908
8380
|
} : {},
|
|
5909
|
-
...
|
|
5910
|
-
error:
|
|
8381
|
+
...row2.error !== void 0 ? {
|
|
8382
|
+
error: row2.error
|
|
5911
8383
|
} : {}
|
|
5912
8384
|
});
|
|
5913
8385
|
}
|
|
@@ -5916,38 +8388,38 @@ var InMemoryAgentStore = class {
|
|
|
5916
8388
|
}
|
|
5917
8389
|
async failUnsettledToolCalls(runId, error) {
|
|
5918
8390
|
let settled = 0;
|
|
5919
|
-
for (const
|
|
5920
|
-
if (
|
|
5921
|
-
|
|
5922
|
-
|
|
8391
|
+
for (const row2 of this.toolCalls.values()) {
|
|
8392
|
+
if (row2.runId === runId && row2.status === "pending_approval") {
|
|
8393
|
+
row2.status = "failed";
|
|
8394
|
+
row2.error = error;
|
|
5923
8395
|
settled += 1;
|
|
5924
8396
|
}
|
|
5925
8397
|
}
|
|
5926
8398
|
return settled;
|
|
5927
8399
|
}
|
|
5928
8400
|
async updateToolCall(input) {
|
|
5929
|
-
const
|
|
5930
|
-
if (
|
|
8401
|
+
const row2 = this.toolCalls.get(input.toolCallId);
|
|
8402
|
+
if (row2 === void 0) {
|
|
5931
8403
|
return;
|
|
5932
8404
|
}
|
|
5933
|
-
|
|
8405
|
+
row2.status = input.status;
|
|
5934
8406
|
if (input.output !== void 0) {
|
|
5935
|
-
|
|
8407
|
+
row2.output = input.output;
|
|
5936
8408
|
}
|
|
5937
8409
|
if (input.error !== void 0) {
|
|
5938
|
-
|
|
8410
|
+
row2.error = input.error;
|
|
5939
8411
|
}
|
|
5940
8412
|
if (input.executionMs !== void 0) {
|
|
5941
|
-
|
|
8413
|
+
row2.executionMs = input.executionMs;
|
|
5942
8414
|
}
|
|
5943
8415
|
if (input.executedByRef !== void 0) {
|
|
5944
|
-
|
|
8416
|
+
row2.executedByRef = input.executedByRef;
|
|
5945
8417
|
}
|
|
5946
8418
|
if (input.remember !== void 0) {
|
|
5947
|
-
|
|
8419
|
+
row2.remember = input.remember;
|
|
5948
8420
|
}
|
|
5949
8421
|
if (input.decidedVia !== void 0) {
|
|
5950
|
-
|
|
8422
|
+
row2.decidedVia = input.decidedVia;
|
|
5951
8423
|
}
|
|
5952
8424
|
}
|
|
5953
8425
|
async recordUsage(input) {
|
|
@@ -5975,9 +8447,9 @@ var InMemoryAgentStore = class {
|
|
|
5975
8447
|
return this.usageBetween(actorRef, day, day);
|
|
5976
8448
|
}
|
|
5977
8449
|
async usageBetween(actorRef, fromDay, toDay) {
|
|
5978
|
-
const rows = this.usage.filter((
|
|
5979
|
-
const usedTokens = rows.reduce((sum,
|
|
5980
|
-
const costUsd = rows.reduce((sum,
|
|
8450
|
+
const rows = this.usage.filter((row2) => row2.actorRef === actorRef && row2.day >= fromDay && row2.day <= toDay);
|
|
8451
|
+
const usedTokens = rows.reduce((sum, row2) => sum + row2.inputTokens + row2.outputTokens, 0);
|
|
8452
|
+
const costUsd = rows.reduce((sum, row2) => sum + (row2.costUsd ?? 0), 0);
|
|
5981
8453
|
return {
|
|
5982
8454
|
usedTokens,
|
|
5983
8455
|
costUsd
|
|
@@ -5985,30 +8457,30 @@ var InMemoryAgentStore = class {
|
|
|
5985
8457
|
}
|
|
5986
8458
|
/** Test helper: read the recorded usage rows (modelId + token totals). */
|
|
5987
8459
|
usageRows() {
|
|
5988
|
-
return this.usage.map((
|
|
5989
|
-
actorRef:
|
|
5990
|
-
tokens:
|
|
5991
|
-
modelId:
|
|
8460
|
+
return this.usage.map((row2) => ({
|
|
8461
|
+
actorRef: row2.actorRef,
|
|
8462
|
+
tokens: row2.inputTokens + row2.outputTokens,
|
|
8463
|
+
modelId: row2.modelId
|
|
5992
8464
|
}));
|
|
5993
8465
|
}
|
|
5994
8466
|
/** Governance read-model feed: recorded usage rows with the input/output split + thread/day. */
|
|
5995
8467
|
governanceUsage() {
|
|
5996
|
-
return this.usage.map((
|
|
5997
|
-
actorRef:
|
|
5998
|
-
threadId:
|
|
5999
|
-
modelId:
|
|
6000
|
-
inputTokens:
|
|
6001
|
-
outputTokens:
|
|
6002
|
-
day:
|
|
6003
|
-
createdAt:
|
|
6004
|
-
...
|
|
6005
|
-
cacheWriteTokens:
|
|
8468
|
+
return this.usage.map((row2) => ({
|
|
8469
|
+
actorRef: row2.actorRef,
|
|
8470
|
+
threadId: row2.threadId,
|
|
8471
|
+
modelId: row2.modelId,
|
|
8472
|
+
inputTokens: row2.inputTokens,
|
|
8473
|
+
outputTokens: row2.outputTokens,
|
|
8474
|
+
day: row2.day,
|
|
8475
|
+
createdAt: row2.createdAt,
|
|
8476
|
+
...row2.cacheWriteTokens !== void 0 ? {
|
|
8477
|
+
cacheWriteTokens: row2.cacheWriteTokens
|
|
6006
8478
|
} : {},
|
|
6007
|
-
...
|
|
6008
|
-
cacheReadTokens:
|
|
8479
|
+
...row2.cacheReadTokens !== void 0 ? {
|
|
8480
|
+
cacheReadTokens: row2.cacheReadTokens
|
|
6009
8481
|
} : {},
|
|
6010
|
-
...
|
|
6011
|
-
costUsd:
|
|
8482
|
+
...row2.costUsd !== void 0 ? {
|
|
8483
|
+
costUsd: row2.costUsd
|
|
6012
8484
|
} : {}
|
|
6013
8485
|
}));
|
|
6014
8486
|
}
|
|
@@ -6016,22 +8488,22 @@ var InMemoryAgentStore = class {
|
|
|
6016
8488
|
governanceToolCalls() {
|
|
6017
8489
|
return [
|
|
6018
8490
|
...this.toolCalls.values()
|
|
6019
|
-
].map((
|
|
6020
|
-
toolCallId:
|
|
6021
|
-
toolName:
|
|
6022
|
-
toolType:
|
|
6023
|
-
status:
|
|
6024
|
-
threadId:
|
|
6025
|
-
messageId:
|
|
6026
|
-
createdAt:
|
|
6027
|
-
...
|
|
6028
|
-
executionMs:
|
|
8491
|
+
].map((row2) => ({
|
|
8492
|
+
toolCallId: row2.toolCallId,
|
|
8493
|
+
toolName: row2.toolName,
|
|
8494
|
+
toolType: row2.toolType,
|
|
8495
|
+
status: row2.status,
|
|
8496
|
+
threadId: row2.threadId,
|
|
8497
|
+
messageId: row2.messageId,
|
|
8498
|
+
createdAt: row2.createdAt,
|
|
8499
|
+
...row2.executionMs !== void 0 ? {
|
|
8500
|
+
executionMs: row2.executionMs
|
|
6029
8501
|
} : {},
|
|
6030
|
-
...
|
|
6031
|
-
error:
|
|
8502
|
+
...row2.error !== void 0 ? {
|
|
8503
|
+
error: row2.error
|
|
6032
8504
|
} : {},
|
|
6033
|
-
...
|
|
6034
|
-
runId:
|
|
8505
|
+
...row2.runId !== void 0 ? {
|
|
8506
|
+
runId: row2.runId
|
|
6035
8507
|
} : {}
|
|
6036
8508
|
}));
|
|
6037
8509
|
}
|
|
@@ -6091,51 +8563,51 @@ var InMemoryAgentStore = class {
|
|
|
6091
8563
|
governanceThreads() {
|
|
6092
8564
|
return [
|
|
6093
8565
|
...this.threads.values()
|
|
6094
|
-
].map((
|
|
6095
|
-
threadId:
|
|
6096
|
-
title:
|
|
6097
|
-
actorRef:
|
|
6098
|
-
messageCount:
|
|
6099
|
-
updatedAt:
|
|
8566
|
+
].map((row2) => ({
|
|
8567
|
+
threadId: row2.id,
|
|
8568
|
+
title: row2.title,
|
|
8569
|
+
actorRef: row2.actorRef,
|
|
8570
|
+
messageCount: row2.messages.length,
|
|
8571
|
+
updatedAt: row2.updatedAt
|
|
6100
8572
|
}));
|
|
6101
8573
|
}
|
|
6102
8574
|
/** Governance read-model feed: recorded run outcomes (the reliability surfaces). */
|
|
6103
8575
|
governanceRuns() {
|
|
6104
8576
|
return [
|
|
6105
8577
|
...this.runs.values()
|
|
6106
|
-
].map((
|
|
6107
|
-
runId:
|
|
6108
|
-
threadId:
|
|
6109
|
-
actorRef:
|
|
6110
|
-
status:
|
|
6111
|
-
retries:
|
|
6112
|
-
startedAt:
|
|
6113
|
-
...
|
|
6114
|
-
agentName:
|
|
8578
|
+
].map((row2) => ({
|
|
8579
|
+
runId: row2.runId,
|
|
8580
|
+
threadId: row2.threadId,
|
|
8581
|
+
actorRef: row2.actorRef,
|
|
8582
|
+
status: row2.status,
|
|
8583
|
+
retries: row2.retries,
|
|
8584
|
+
startedAt: row2.startedAt,
|
|
8585
|
+
...row2.agentName !== void 0 ? {
|
|
8586
|
+
agentName: row2.agentName
|
|
6115
8587
|
} : {},
|
|
6116
|
-
...
|
|
6117
|
-
parentRunId:
|
|
8588
|
+
...row2.parentRunId !== void 0 ? {
|
|
8589
|
+
parentRunId: row2.parentRunId
|
|
6118
8590
|
} : {},
|
|
6119
|
-
...
|
|
6120
|
-
durationMs:
|
|
8591
|
+
...row2.durationMs !== void 0 ? {
|
|
8592
|
+
durationMs: row2.durationMs
|
|
6121
8593
|
} : {},
|
|
6122
|
-
...
|
|
6123
|
-
errorCode:
|
|
8594
|
+
...row2.errorCode !== void 0 ? {
|
|
8595
|
+
errorCode: row2.errorCode
|
|
6124
8596
|
} : {},
|
|
6125
|
-
...
|
|
6126
|
-
errorMessage:
|
|
8597
|
+
...row2.errorMessage !== void 0 ? {
|
|
8598
|
+
errorMessage: row2.errorMessage
|
|
6127
8599
|
} : {},
|
|
6128
|
-
...
|
|
6129
|
-
settledAt:
|
|
8600
|
+
...row2.settledAt !== void 0 ? {
|
|
8601
|
+
settledAt: row2.settledAt
|
|
6130
8602
|
} : {},
|
|
6131
|
-
...
|
|
6132
|
-
promptHash:
|
|
8603
|
+
...row2.promptHash !== void 0 ? {
|
|
8604
|
+
promptHash: row2.promptHash
|
|
6133
8605
|
} : {}
|
|
6134
8606
|
}));
|
|
6135
8607
|
}
|
|
6136
8608
|
threadIdForMessage(messageId) {
|
|
6137
|
-
for (const [threadId,
|
|
6138
|
-
if (
|
|
8609
|
+
for (const [threadId, row2] of this.threads) {
|
|
8610
|
+
if (row2.messages.some((message) => message.id === messageId)) {
|
|
6139
8611
|
return threadId;
|
|
6140
8612
|
}
|
|
6141
8613
|
}
|
|
@@ -6145,77 +8617,77 @@ var InMemoryAgentStore = class {
|
|
|
6145
8617
|
toolCallRows() {
|
|
6146
8618
|
return [
|
|
6147
8619
|
...this.toolCalls.values()
|
|
6148
|
-
].map((
|
|
6149
|
-
toolCallId:
|
|
6150
|
-
toolName:
|
|
6151
|
-
toolType:
|
|
6152
|
-
status:
|
|
6153
|
-
input:
|
|
6154
|
-
...
|
|
6155
|
-
output:
|
|
8620
|
+
].map((row2) => ({
|
|
8621
|
+
toolCallId: row2.toolCallId,
|
|
8622
|
+
toolName: row2.toolName,
|
|
8623
|
+
toolType: row2.toolType,
|
|
8624
|
+
status: row2.status,
|
|
8625
|
+
input: row2.input,
|
|
8626
|
+
...row2.output !== void 0 ? {
|
|
8627
|
+
output: row2.output
|
|
6156
8628
|
} : {},
|
|
6157
|
-
...
|
|
6158
|
-
error:
|
|
8629
|
+
...row2.error !== void 0 ? {
|
|
8630
|
+
error: row2.error
|
|
6159
8631
|
} : {},
|
|
6160
|
-
...
|
|
6161
|
-
runId:
|
|
8632
|
+
...row2.runId !== void 0 ? {
|
|
8633
|
+
runId: row2.runId
|
|
6162
8634
|
} : {},
|
|
6163
|
-
...
|
|
6164
|
-
executedByRef:
|
|
8635
|
+
...row2.executedByRef !== void 0 ? {
|
|
8636
|
+
executedByRef: row2.executedByRef
|
|
6165
8637
|
} : {},
|
|
6166
|
-
...
|
|
6167
|
-
approver:
|
|
8638
|
+
...row2.approver !== void 0 ? {
|
|
8639
|
+
approver: row2.approver
|
|
6168
8640
|
} : {},
|
|
6169
|
-
...
|
|
6170
|
-
expiresAt:
|
|
8641
|
+
...row2.expiresAt !== void 0 ? {
|
|
8642
|
+
expiresAt: row2.expiresAt
|
|
6171
8643
|
} : {},
|
|
6172
|
-
...
|
|
6173
|
-
remember:
|
|
8644
|
+
...row2.remember !== void 0 ? {
|
|
8645
|
+
remember: row2.remember
|
|
6174
8646
|
} : {},
|
|
6175
|
-
...
|
|
6176
|
-
decidedVia:
|
|
8647
|
+
...row2.decidedVia !== void 0 ? {
|
|
8648
|
+
decidedVia: row2.decidedVia
|
|
6177
8649
|
} : {}
|
|
6178
8650
|
}));
|
|
6179
8651
|
}
|
|
6180
|
-
toSummary(
|
|
6181
|
-
const last =
|
|
8652
|
+
toSummary(row2) {
|
|
8653
|
+
const last = row2.messages[row2.messages.length - 1];
|
|
6182
8654
|
return {
|
|
6183
|
-
id:
|
|
6184
|
-
title:
|
|
6185
|
-
transient:
|
|
6186
|
-
createdAt:
|
|
6187
|
-
updatedAt:
|
|
8655
|
+
id: row2.id,
|
|
8656
|
+
title: row2.title,
|
|
8657
|
+
transient: row2.transient,
|
|
8658
|
+
createdAt: row2.createdAt,
|
|
8659
|
+
updatedAt: row2.updatedAt,
|
|
6188
8660
|
...last !== void 0 ? {
|
|
6189
8661
|
lastMessagePreview: last.content.slice(0, 120)
|
|
6190
8662
|
} : {},
|
|
6191
|
-
defaultAgent:
|
|
6192
|
-
...
|
|
6193
|
-
model:
|
|
8663
|
+
defaultAgent: row2.defaultAgent ?? null,
|
|
8664
|
+
...row2.model != null ? {
|
|
8665
|
+
model: row2.model
|
|
6194
8666
|
} : {},
|
|
6195
|
-
persona:
|
|
8667
|
+
persona: row2.persona ?? null
|
|
6196
8668
|
};
|
|
6197
8669
|
}
|
|
6198
8670
|
};
|
|
6199
8671
|
|
|
6200
8672
|
// src/confirm-token.ts
|
|
6201
|
-
var
|
|
8673
|
+
var import_node_crypto3 = require("crypto");
|
|
6202
8674
|
var DEFAULT_CONFIRM_TTL_MS = 15 * 60 * 1e3;
|
|
6203
|
-
function
|
|
8675
|
+
function canonicalJson2(value) {
|
|
6204
8676
|
if (value === void 0) return "null";
|
|
6205
8677
|
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
6206
|
-
if (Array.isArray(value)) return `[${value.map(
|
|
8678
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson2).join(",")}]`;
|
|
6207
8679
|
if (typeof value.toJSON === "function") {
|
|
6208
|
-
return
|
|
8680
|
+
return canonicalJson2(value.toJSON());
|
|
6209
8681
|
}
|
|
6210
8682
|
const entries = Object.entries(value).filter(([, entry]) => entry !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
6211
|
-
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${
|
|
8683
|
+
return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${canonicalJson2(entry)}`).join(",")}}`;
|
|
6212
8684
|
}
|
|
6213
|
-
__name(
|
|
8685
|
+
__name(canonicalJson2, "canonicalJson");
|
|
6214
8686
|
function signature(subject, expiresAt, secret) {
|
|
6215
8687
|
if (secret === "") {
|
|
6216
8688
|
throw new Error("confirm token: the secret is empty");
|
|
6217
8689
|
}
|
|
6218
|
-
return (0,
|
|
8690
|
+
return (0, import_node_crypto3.createHmac)("sha256", secret).update(canonicalJson2([
|
|
6219
8691
|
"agent-confirm",
|
|
6220
8692
|
subject.tool,
|
|
6221
8693
|
subject.actorId,
|
|
@@ -6242,11 +8714,11 @@ function verifyConfirmToken(token, subject, options) {
|
|
|
6242
8714
|
if (expiresAt === void 0 || expiresAt < (options.now ?? Date.now())) return false;
|
|
6243
8715
|
const expected = Buffer.from(signature(subject, expiresAt, options.secret));
|
|
6244
8716
|
const given = Buffer.from(token.slice(token.indexOf(".") + 1));
|
|
6245
|
-
return expected.length === given.length && (0,
|
|
8717
|
+
return expected.length === given.length && (0, import_node_crypto3.timingSafeEqual)(expected, given);
|
|
6246
8718
|
}
|
|
6247
8719
|
__name(verifyConfirmToken, "verifyConfirmToken");
|
|
6248
8720
|
function hashConfirmToken(token) {
|
|
6249
|
-
return (0,
|
|
8721
|
+
return (0, import_node_crypto3.createHash)("sha256").update(token).digest("hex");
|
|
6250
8722
|
}
|
|
6251
8723
|
__name(hashConfirmToken, "hashConfirmToken");
|
|
6252
8724
|
var InMemoryConfirmTokenStore = class {
|
|
@@ -6394,12 +8866,12 @@ function withConfirmFields(schema) {
|
|
|
6394
8866
|
});
|
|
6395
8867
|
}
|
|
6396
8868
|
const { args, fields } = splitConfirm(value);
|
|
6397
|
-
const
|
|
6398
|
-
if (
|
|
8869
|
+
const result2 = await inner.validate(args);
|
|
8870
|
+
if (result2.issues !== void 0) {
|
|
6399
8871
|
return {
|
|
6400
8872
|
issues: [
|
|
6401
8873
|
...issues,
|
|
6402
|
-
...
|
|
8874
|
+
...result2.issues
|
|
6403
8875
|
]
|
|
6404
8876
|
};
|
|
6405
8877
|
}
|
|
@@ -6409,10 +8881,10 @@ function withConfirmFields(schema) {
|
|
|
6409
8881
|
};
|
|
6410
8882
|
}
|
|
6411
8883
|
return {
|
|
6412
|
-
value: isRecord(
|
|
6413
|
-
...
|
|
8884
|
+
value: isRecord(result2.value) ? {
|
|
8885
|
+
...result2.value,
|
|
6414
8886
|
...fields
|
|
6415
|
-
} :
|
|
8887
|
+
} : result2.value
|
|
6416
8888
|
};
|
|
6417
8889
|
}, "validate"),
|
|
6418
8890
|
jsonSchema: {
|
|
@@ -6543,8 +9015,8 @@ var SqlTokenStreamSink = class {
|
|
|
6543
9015
|
autoPurge;
|
|
6544
9016
|
writes = /* @__PURE__ */ new Map();
|
|
6545
9017
|
lastAutoPurge = 0;
|
|
6546
|
-
constructor(
|
|
6547
|
-
this.table =
|
|
9018
|
+
constructor(table2, options = {}) {
|
|
9019
|
+
this.table = table2;
|
|
6548
9020
|
this.pollIntervalMs = Math.max(1, options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
6549
9021
|
this.idlePollIntervalMs = Math.max(this.pollIntervalMs, options.idlePollIntervalMs ?? DEFAULT_IDLE_POLL_INTERVAL_MS);
|
|
6550
9022
|
this.flushMs = Math.max(0, options.flushMs ?? DEFAULT_FLUSH_MS);
|
|
@@ -6686,15 +9158,15 @@ var SqlTokenStreamSink = class {
|
|
|
6686
9158
|
let quietSince = Date.now();
|
|
6687
9159
|
while (true) {
|
|
6688
9160
|
const rows = await this.table.read(runId, cursor, READ_PAGE);
|
|
6689
|
-
for (const
|
|
6690
|
-
cursor =
|
|
6691
|
-
if (
|
|
6692
|
-
if (
|
|
6693
|
-
throw new AgentStreamError(JSON.parse(
|
|
9161
|
+
for (const row2 of rows) {
|
|
9162
|
+
cursor = row2.seq;
|
|
9163
|
+
if (row2.frame === null) {
|
|
9164
|
+
if (row2.error !== null) {
|
|
9165
|
+
throw new AgentStreamError(JSON.parse(row2.error));
|
|
6694
9166
|
}
|
|
6695
9167
|
return;
|
|
6696
9168
|
}
|
|
6697
|
-
yield encoder2.encode(
|
|
9169
|
+
yield encoder2.encode(row2.frame);
|
|
6698
9170
|
}
|
|
6699
9171
|
if (rows.length > 0) {
|
|
6700
9172
|
quietSince = Date.now();
|
|
@@ -6744,6 +9216,436 @@ var SqlTokenStreamSink = class {
|
|
|
6744
9216
|
});
|
|
6745
9217
|
}
|
|
6746
9218
|
};
|
|
9219
|
+
|
|
9220
|
+
// src/action-proposal-text.ts
|
|
9221
|
+
function resolveTextActionProposalDecision(text, proposals, vocabulary) {
|
|
9222
|
+
const command = parseTextActionProposalCommand(text, vocabulary);
|
|
9223
|
+
if (command.status === "unmatched") return command;
|
|
9224
|
+
const { decision, remember } = command;
|
|
9225
|
+
const pending = proposals.filter((proposal) => proposal.decision === "pending");
|
|
9226
|
+
const explicitId = command.proposalId;
|
|
9227
|
+
if (explicitId !== void 0) {
|
|
9228
|
+
if (!pending.some((proposal) => proposal.id === explicitId)) return {
|
|
9229
|
+
status: "unmatched"
|
|
9230
|
+
};
|
|
9231
|
+
return {
|
|
9232
|
+
status: "decision",
|
|
9233
|
+
proposalId: explicitId,
|
|
9234
|
+
decision,
|
|
9235
|
+
remember
|
|
9236
|
+
};
|
|
9237
|
+
}
|
|
9238
|
+
if (pending.length === 0) return {
|
|
9239
|
+
status: "unmatched"
|
|
9240
|
+
};
|
|
9241
|
+
if (pending.length > 1) return {
|
|
9242
|
+
status: "ambiguous",
|
|
9243
|
+
proposalIds: pending.map(({ id }) => id)
|
|
9244
|
+
};
|
|
9245
|
+
const candidate = pending[0];
|
|
9246
|
+
if (!candidate) return {
|
|
9247
|
+
status: "unmatched"
|
|
9248
|
+
};
|
|
9249
|
+
return {
|
|
9250
|
+
status: "decision",
|
|
9251
|
+
proposalId: candidate.id,
|
|
9252
|
+
decision,
|
|
9253
|
+
remember
|
|
9254
|
+
};
|
|
9255
|
+
}
|
|
9256
|
+
__name(resolveTextActionProposalDecision, "resolveTextActionProposalDecision");
|
|
9257
|
+
var DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY = {
|
|
9258
|
+
approve: [
|
|
9259
|
+
"yes",
|
|
9260
|
+
"confirm",
|
|
9261
|
+
"approve",
|
|
9262
|
+
"approved",
|
|
9263
|
+
"ok"
|
|
9264
|
+
],
|
|
9265
|
+
reject: [
|
|
9266
|
+
"no",
|
|
9267
|
+
"cancel",
|
|
9268
|
+
"reject",
|
|
9269
|
+
"deny"
|
|
9270
|
+
],
|
|
9271
|
+
remember: [
|
|
9272
|
+
"always in this conversation"
|
|
9273
|
+
]
|
|
9274
|
+
};
|
|
9275
|
+
var DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES = {
|
|
9276
|
+
approved: "Proposal approved and queued to run.",
|
|
9277
|
+
rejected: "Proposal rejected; nothing was run.",
|
|
9278
|
+
expired: "The proposal expired; nothing was run.",
|
|
9279
|
+
unchanged: "This proposal could not be changed; refresh the list to see where it stands.",
|
|
9280
|
+
ambiguous: /* @__PURE__ */ __name((ids) => `Which proposal? Reply confirm #ID or cancel #ID: ${ids.join(", ")}`, "ambiguous"),
|
|
9281
|
+
tooMany: "There are several proposals. Confirm or reject one with an explicit #ID."
|
|
9282
|
+
};
|
|
9283
|
+
function textActionProposalReply(result2, decision, replies = DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES) {
|
|
9284
|
+
return result2.status === "expired" || result2.proposal?.decision === "expired" ? replies.expired : result2.status === "applied" || result2.status === "unchanged" ? decision === "approved" ? replies.approved : replies.rejected : replies.unchanged;
|
|
9285
|
+
}
|
|
9286
|
+
__name(textActionProposalReply, "textActionProposalReply");
|
|
9287
|
+
var escapeRegExp = /* @__PURE__ */ __name((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "escapeRegExp");
|
|
9288
|
+
var alternatives = /* @__PURE__ */ __name((words) => words.map((word) => word.trim()).filter((word) => word.length > 0).map((word) => escapeRegExp(word).replace(/\s+/g, "\\s+")).join("|"), "alternatives");
|
|
9289
|
+
var fold = /* @__PURE__ */ __name((word) => word.trim().toLowerCase(), "fold");
|
|
9290
|
+
function parseTextActionProposalCommand(text, vocabulary = DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY) {
|
|
9291
|
+
if (/[\r\n]/u.test(text)) return {
|
|
9292
|
+
status: "unmatched"
|
|
9293
|
+
};
|
|
9294
|
+
const verbs = alternatives([
|
|
9295
|
+
...vocabulary.approve,
|
|
9296
|
+
...vocabulary.reject
|
|
9297
|
+
]);
|
|
9298
|
+
if (verbs.length === 0) return {
|
|
9299
|
+
status: "unmatched"
|
|
9300
|
+
};
|
|
9301
|
+
const remember = alternatives(vocabulary.remember);
|
|
9302
|
+
const match = new RegExp(`^(${verbs})${remember.length > 0 ? `(?: (${remember}))?` : "()"}(?: #([^\\s]+?))?[.!]?$`, "iu").exec(text.trim());
|
|
9303
|
+
if (!match) return {
|
|
9304
|
+
status: "unmatched"
|
|
9305
|
+
};
|
|
9306
|
+
const verb = match[1] === void 0 ? void 0 : fold(match[1]);
|
|
9307
|
+
if (verb === void 0) return {
|
|
9308
|
+
status: "unmatched"
|
|
9309
|
+
};
|
|
9310
|
+
const decision = vocabulary.reject.some((word) => fold(word) === verb) ? "rejected" : "approved";
|
|
9311
|
+
const remembers = match[2] !== void 0 && match[2] !== "";
|
|
9312
|
+
if (remembers && decision !== "approved") return {
|
|
9313
|
+
status: "unmatched"
|
|
9314
|
+
};
|
|
9315
|
+
return {
|
|
9316
|
+
status: "command",
|
|
9317
|
+
decision,
|
|
9318
|
+
remember: remembers,
|
|
9319
|
+
...match[3] !== void 0 ? {
|
|
9320
|
+
proposalId: match[3]
|
|
9321
|
+
} : {}
|
|
9322
|
+
};
|
|
9323
|
+
}
|
|
9324
|
+
__name(parseTextActionProposalCommand, "parseTextActionProposalCommand");
|
|
9325
|
+
var ptBrActionProposalText = {
|
|
9326
|
+
vocabulary: {
|
|
9327
|
+
approve: [
|
|
9328
|
+
"sim",
|
|
9329
|
+
"confirmo",
|
|
9330
|
+
"confirmar",
|
|
9331
|
+
"aprovar",
|
|
9332
|
+
"aprovo",
|
|
9333
|
+
"pode",
|
|
9334
|
+
...DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY.approve
|
|
9335
|
+
],
|
|
9336
|
+
reject: [
|
|
9337
|
+
"n\xE3o",
|
|
9338
|
+
"nao",
|
|
9339
|
+
"cancelar",
|
|
9340
|
+
"cancela",
|
|
9341
|
+
"rejeitar",
|
|
9342
|
+
"rejeito",
|
|
9343
|
+
...DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY.reject
|
|
9344
|
+
],
|
|
9345
|
+
remember: [
|
|
9346
|
+
"sempre nesta conversa",
|
|
9347
|
+
...DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY.remember
|
|
9348
|
+
]
|
|
9349
|
+
},
|
|
9350
|
+
replies: {
|
|
9351
|
+
approved: "Proposta aprovada e enfileirada para execu\xE7\xE3o.",
|
|
9352
|
+
rejected: "Proposta rejeitada; nenhuma a\xE7\xE3o foi executada.",
|
|
9353
|
+
expired: "A proposta expirou; nenhuma a\xE7\xE3o foi executada.",
|
|
9354
|
+
unchanged: "N\xE3o foi poss\xEDvel alterar esta proposta; atualize a lista para consultar seu estado.",
|
|
9355
|
+
ambiguous: /* @__PURE__ */ __name((ids) => `Qual proposta? Responda confirmar #ID ou cancelar #ID: ${ids.join(", ")}`, "ambiguous"),
|
|
9356
|
+
tooMany: "H\xE1 v\xE1rias propostas. Confirme ou rejeite usando #ID expl\xEDcito."
|
|
9357
|
+
}
|
|
9358
|
+
};
|
|
9359
|
+
|
|
9360
|
+
// src/action-proposal-view.ts
|
|
9361
|
+
function toActionProposalView(proposal) {
|
|
9362
|
+
const { execution, outcomeDelivery, idempotencyKey: _idempotencyKey, preparationInput: _preparationInput, executionContext: _executionContext, ...rest } = proposal;
|
|
9363
|
+
return {
|
|
9364
|
+
...rest,
|
|
9365
|
+
execution: execution === null ? null : withoutLease(execution),
|
|
9366
|
+
...outcomeDelivery !== void 0 ? {
|
|
9367
|
+
outcomeDelivery: withoutLease(outcomeDelivery)
|
|
9368
|
+
} : {}
|
|
9369
|
+
};
|
|
9370
|
+
}
|
|
9371
|
+
__name(toActionProposalView, "toActionProposalView");
|
|
9372
|
+
function toActionProposalMutationView(result2) {
|
|
9373
|
+
const { proposal, ...rest } = result2;
|
|
9374
|
+
return {
|
|
9375
|
+
...rest,
|
|
9376
|
+
...proposal !== void 0 ? {
|
|
9377
|
+
proposal: toActionProposalView(proposal)
|
|
9378
|
+
} : {}
|
|
9379
|
+
};
|
|
9380
|
+
}
|
|
9381
|
+
__name(toActionProposalMutationView, "toActionProposalMutationView");
|
|
9382
|
+
function withoutLease(value) {
|
|
9383
|
+
const { lease: _lease, ...rest } = value;
|
|
9384
|
+
return rest;
|
|
9385
|
+
}
|
|
9386
|
+
__name(withoutLease, "withoutLease");
|
|
9387
|
+
|
|
9388
|
+
// src/action-proposal-executor.ts
|
|
9389
|
+
var ActionProposalExecutor = class {
|
|
9390
|
+
static {
|
|
9391
|
+
__name(this, "ActionProposalExecutor");
|
|
9392
|
+
}
|
|
9393
|
+
options;
|
|
9394
|
+
constructor(options) {
|
|
9395
|
+
this.options = options;
|
|
9396
|
+
}
|
|
9397
|
+
async execute(proposal) {
|
|
9398
|
+
let ui = createNegotiatedUiCollector(proposal.originToolCallId, {
|
|
9399
|
+
actor: {
|
|
9400
|
+
id: proposal.actorRef
|
|
9401
|
+
},
|
|
9402
|
+
threadId: proposal.threadId
|
|
9403
|
+
});
|
|
9404
|
+
try {
|
|
9405
|
+
const actor = await this.options.resolver.resolve({
|
|
9406
|
+
actorRef: proposal.actorRef,
|
|
9407
|
+
tenantRef: proposal.tenantRef
|
|
9408
|
+
});
|
|
9409
|
+
if (!actor || actor.id !== proposal.actorRef || (actor.tenantRef ?? null) !== proposal.tenantRef) throw new Error("Action proposal requester no longer exists or scope changed");
|
|
9410
|
+
const deps = await this.options.resolveExecution(proposal, actor);
|
|
9411
|
+
if (deps.registry.spec(proposal.toolName)?.kind !== "action") throw new Error("Action proposal tool no longer exists as an action");
|
|
9412
|
+
const context = proposal.executionContext;
|
|
9413
|
+
ui = createNegotiatedUiCollector(proposal.originToolCallId, {
|
|
9414
|
+
actor,
|
|
9415
|
+
threadId: proposal.threadId,
|
|
9416
|
+
...context?.agentName !== void 0 ? {
|
|
9417
|
+
agentName: context.agentName
|
|
9418
|
+
} : {},
|
|
9419
|
+
...context?.uiCapabilities !== void 0 ? {
|
|
9420
|
+
uiCapabilities: context.uiCapabilities
|
|
9421
|
+
} : {}
|
|
9422
|
+
}, deps.resolveUiCatalog);
|
|
9423
|
+
const output = await deps.registry.invoke(proposal.toolName, snapshotActionProposal(Object.hasOwn(proposal, "preparationInput") ? proposal.preparationInput : proposal.input), {
|
|
9424
|
+
actor,
|
|
9425
|
+
threadId: proposal.threadId,
|
|
9426
|
+
runId: proposal.originRunId,
|
|
9427
|
+
requestId: context?.requestId ?? proposal.originRunId,
|
|
9428
|
+
toolCallId: proposal.originToolCallId,
|
|
9429
|
+
idempotencyKey: proposal.idempotencyKey,
|
|
9430
|
+
...context?.agentName !== void 0 ? {
|
|
9431
|
+
agentName: context.agentName
|
|
9432
|
+
} : {},
|
|
9433
|
+
...context?.persona !== void 0 ? {
|
|
9434
|
+
persona: context.persona
|
|
9435
|
+
} : {},
|
|
9436
|
+
...context?.pageContext !== void 0 ? {
|
|
9437
|
+
pageContext: context.pageContext
|
|
9438
|
+
} : {},
|
|
9439
|
+
...context?.uiCapabilities !== void 0 ? {
|
|
9440
|
+
uiCapabilities: context.uiCapabilities
|
|
9441
|
+
} : {},
|
|
9442
|
+
...deps.host !== void 0 ? {
|
|
9443
|
+
host: deps.host
|
|
9444
|
+
} : {},
|
|
9445
|
+
emitUi: ui.emit
|
|
9446
|
+
}, deps.rolesPolicy, {
|
|
9447
|
+
approvedInput: proposal.input,
|
|
9448
|
+
...deps.allowedTools !== void 0 ? {
|
|
9449
|
+
allowedTools: deps.allowedTools
|
|
9450
|
+
} : {}
|
|
9451
|
+
});
|
|
9452
|
+
return snapshotActionProposal({
|
|
9453
|
+
status: "succeeded",
|
|
9454
|
+
...output !== void 0 ? {
|
|
9455
|
+
result: output
|
|
9456
|
+
} : {},
|
|
9457
|
+
ui: ui.components(),
|
|
9458
|
+
...ui.text() ? {
|
|
9459
|
+
text: ui.text()
|
|
9460
|
+
} : {}
|
|
9461
|
+
});
|
|
9462
|
+
} catch (error) {
|
|
9463
|
+
return {
|
|
9464
|
+
status: "failed",
|
|
9465
|
+
error: error instanceof Error ? error.message : String(error),
|
|
9466
|
+
ui: ui.components(),
|
|
9467
|
+
...ui.text() ? {
|
|
9468
|
+
text: ui.text()
|
|
9469
|
+
} : {}
|
|
9470
|
+
};
|
|
9471
|
+
}
|
|
9472
|
+
}
|
|
9473
|
+
};
|
|
9474
|
+
|
|
9475
|
+
// src/action-proposal-worker.ts
|
|
9476
|
+
var ActionProposalWorker = class {
|
|
9477
|
+
static {
|
|
9478
|
+
__name(this, "ActionProposalWorker");
|
|
9479
|
+
}
|
|
9480
|
+
options;
|
|
9481
|
+
leaseMs;
|
|
9482
|
+
pollIntervalMs;
|
|
9483
|
+
maxConcurrency;
|
|
9484
|
+
timer;
|
|
9485
|
+
stopped = false;
|
|
9486
|
+
renewals = /* @__PURE__ */ new Set();
|
|
9487
|
+
active;
|
|
9488
|
+
constructor(options) {
|
|
9489
|
+
this.options = options;
|
|
9490
|
+
this.leaseMs = options.leaseMs ?? 3e4;
|
|
9491
|
+
this.pollIntervalMs = options.pollIntervalMs ?? 1e3;
|
|
9492
|
+
this.maxConcurrency = options.maxConcurrency ?? 1;
|
|
9493
|
+
for (const value of [
|
|
9494
|
+
this.leaseMs,
|
|
9495
|
+
this.pollIntervalMs,
|
|
9496
|
+
this.maxConcurrency
|
|
9497
|
+
]) if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError("Worker configuration must be positive safe integers");
|
|
9498
|
+
if (this.pollIntervalMs >= this.leaseMs / 3) throw new RangeError("Worker poll interval must be below one third of lease");
|
|
9499
|
+
if (!options.workerId) throw new TypeError("workerId is required");
|
|
9500
|
+
}
|
|
9501
|
+
start() {
|
|
9502
|
+
if (this.timer !== void 0 || this.stopped) return;
|
|
9503
|
+
const tick = /* @__PURE__ */ __name(async () => {
|
|
9504
|
+
if (this.stopped) return;
|
|
9505
|
+
try {
|
|
9506
|
+
await this.runOnce();
|
|
9507
|
+
} catch (error) {
|
|
9508
|
+
this.options.onError?.(error);
|
|
9509
|
+
}
|
|
9510
|
+
if (!this.stopped) this.timer = setTimeout(tick, this.pollIntervalMs);
|
|
9511
|
+
}, "tick");
|
|
9512
|
+
this.timer = setTimeout(tick, 0);
|
|
9513
|
+
}
|
|
9514
|
+
async stop() {
|
|
9515
|
+
this.stopped = true;
|
|
9516
|
+
for (const timer of this.renewals) clearInterval(timer);
|
|
9517
|
+
this.renewals.clear();
|
|
9518
|
+
if (this.timer !== void 0) clearTimeout(this.timer);
|
|
9519
|
+
await this.active;
|
|
9520
|
+
}
|
|
9521
|
+
runOnce() {
|
|
9522
|
+
if (this.active) return this.active;
|
|
9523
|
+
if (this.stopped) return Promise.resolve();
|
|
9524
|
+
const task = this.tick();
|
|
9525
|
+
this.active = task;
|
|
9526
|
+
return task.finally(() => {
|
|
9527
|
+
if (this.active === task) this.active = void 0;
|
|
9528
|
+
});
|
|
9529
|
+
}
|
|
9530
|
+
async tick() {
|
|
9531
|
+
await this.options.store.expireActionProposals({
|
|
9532
|
+
limit: 100
|
|
9533
|
+
});
|
|
9534
|
+
const work = [];
|
|
9535
|
+
for (let index = 0; index < this.maxConcurrency && !this.stopped; index++) {
|
|
9536
|
+
const proposal = await this.options.store.claimNextActionProposal({
|
|
9537
|
+
workerId: this.options.workerId,
|
|
9538
|
+
leaseMs: this.leaseMs
|
|
9539
|
+
});
|
|
9540
|
+
if (!proposal) break;
|
|
9541
|
+
work.push(this.execute(proposal));
|
|
9542
|
+
}
|
|
9543
|
+
await Promise.all(work);
|
|
9544
|
+
for (let index = 0; index < 32 && !this.stopped; index++) {
|
|
9545
|
+
const delivery = await this.options.store.claimNextActionProposalOutcome({
|
|
9546
|
+
workerId: this.options.workerId,
|
|
9547
|
+
leaseMs: this.leaseMs
|
|
9548
|
+
});
|
|
9549
|
+
if (!delivery) break;
|
|
9550
|
+
await this.options.store.admitActionProposalOutcome(delivery.lease);
|
|
9551
|
+
}
|
|
9552
|
+
}
|
|
9553
|
+
async execute(proposal) {
|
|
9554
|
+
const lease = proposal.execution?.lease;
|
|
9555
|
+
if (!lease) throw new Error("Claimed action lacks execution lease");
|
|
9556
|
+
let fenced = true;
|
|
9557
|
+
let renewing;
|
|
9558
|
+
const renew = /* @__PURE__ */ __name(() => {
|
|
9559
|
+
if (renewing || !fenced) return;
|
|
9560
|
+
renewing = this.options.store.extendActionProposalLease(proposal, proposal.id, {
|
|
9561
|
+
token: lease.token,
|
|
9562
|
+
generation: lease.generation,
|
|
9563
|
+
leaseMs: this.leaseMs
|
|
9564
|
+
}).then((result2) => {
|
|
9565
|
+
if (result2.status !== "applied") fenced = false;
|
|
9566
|
+
}, (error) => {
|
|
9567
|
+
fenced = false;
|
|
9568
|
+
this.options.onError?.(error);
|
|
9569
|
+
}).finally(() => {
|
|
9570
|
+
renewing = void 0;
|
|
9571
|
+
});
|
|
9572
|
+
}, "renew");
|
|
9573
|
+
const timer = setInterval(renew, this.leaseMs / 3);
|
|
9574
|
+
this.renewals.add(timer);
|
|
9575
|
+
try {
|
|
9576
|
+
const result2 = await this.options.executor.execute(proposal);
|
|
9577
|
+
clearInterval(timer);
|
|
9578
|
+
await renewing;
|
|
9579
|
+
if (!fenced) return;
|
|
9580
|
+
const settled = await this.options.store.settleActionProposal(proposal, proposal.id, {
|
|
9581
|
+
...result2,
|
|
9582
|
+
token: lease.token,
|
|
9583
|
+
generation: lease.generation
|
|
9584
|
+
});
|
|
9585
|
+
if (settled.status === "applied" && settled.proposal) await this.options.onSettled?.(settled.proposal);
|
|
9586
|
+
} finally {
|
|
9587
|
+
clearInterval(timer);
|
|
9588
|
+
this.renewals.delete(timer);
|
|
9589
|
+
await renewing;
|
|
9590
|
+
}
|
|
9591
|
+
}
|
|
9592
|
+
};
|
|
9593
|
+
|
|
9594
|
+
// src/action-proposal-capabilities.ts
|
|
9595
|
+
function assertIndependentActionCapabilities(store, resolver) {
|
|
9596
|
+
const candidate = store;
|
|
9597
|
+
if (!resolver || typeof resolver.resolve !== "function") throw new Error("Independent action mode requires a BackgroundActorResolver");
|
|
9598
|
+
if (!isChatQueueStore(store) || candidate.actionProposalAdmissionSupported === false) throw new Error("Independent action mode requires transactional thread admission");
|
|
9599
|
+
const required = [
|
|
9600
|
+
"createActionProposal",
|
|
9601
|
+
"getActionProposal",
|
|
9602
|
+
"listActionProposals",
|
|
9603
|
+
"decideActionProposal",
|
|
9604
|
+
"claimActionProposal",
|
|
9605
|
+
"extendActionProposalLease",
|
|
9606
|
+
"settleActionProposal",
|
|
9607
|
+
"claimNextActionProposal",
|
|
9608
|
+
"expireActionProposals",
|
|
9609
|
+
"getThreadActionProposalScope",
|
|
9610
|
+
"claimNextActionProposalOutcome",
|
|
9611
|
+
"admitActionProposalOutcome",
|
|
9612
|
+
"createReplacingActionProposal",
|
|
9613
|
+
"supersedeActionProposal"
|
|
9614
|
+
];
|
|
9615
|
+
if (required.some((method) => typeof candidate[method] !== "function")) throw new Error("Independent action mode requires proposal, worker, outcome and admission capabilities on the conversation store");
|
|
9616
|
+
}
|
|
9617
|
+
__name(assertIndependentActionCapabilities, "assertIndependentActionCapabilities");
|
|
9618
|
+
|
|
9619
|
+
// src/functional-tool.ts
|
|
9620
|
+
function createFunctionalTool(definition) {
|
|
9621
|
+
const { input, execute, present, preflight, isEnabled, canUse, describe, kind, ...metadata } = definition;
|
|
9622
|
+
return {
|
|
9623
|
+
spec: {
|
|
9624
|
+
...metadata,
|
|
9625
|
+
kind: kind ?? "read",
|
|
9626
|
+
inputSchema: input
|
|
9627
|
+
},
|
|
9628
|
+
handler: {
|
|
9629
|
+
execute: execute.bind(definition),
|
|
9630
|
+
...present === void 0 ? {} : {
|
|
9631
|
+
present: present.bind(definition)
|
|
9632
|
+
},
|
|
9633
|
+
...preflight === void 0 ? {} : {
|
|
9634
|
+
preflight: preflight.bind(definition)
|
|
9635
|
+
},
|
|
9636
|
+
...isEnabled === void 0 ? {} : {
|
|
9637
|
+
isEnabled: isEnabled.bind(definition)
|
|
9638
|
+
},
|
|
9639
|
+
...canUse === void 0 ? {} : {
|
|
9640
|
+
canUse: canUse.bind(definition)
|
|
9641
|
+
},
|
|
9642
|
+
...describe === void 0 ? {} : {
|
|
9643
|
+
describe: describe.bind(definition)
|
|
9644
|
+
}
|
|
9645
|
+
}
|
|
9646
|
+
};
|
|
9647
|
+
}
|
|
9648
|
+
__name(createFunctionalTool, "createFunctionalTool");
|
|
6747
9649
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6748
9650
|
0 && (module.exports = {
|
|
6749
9651
|
AGENT_ACTOR_DIRECTORY,
|
|
@@ -6778,6 +9680,8 @@ var SqlTokenStreamSink = class {
|
|
|
6778
9680
|
APPROVAL_EXPIRED_REASON,
|
|
6779
9681
|
ASK_TOOL_DESCRIPTION,
|
|
6780
9682
|
ASK_TOOL_NAME,
|
|
9683
|
+
ActionProposalExecutor,
|
|
9684
|
+
ActionProposalWorker,
|
|
6781
9685
|
AgentRegistry,
|
|
6782
9686
|
AgentStreamError,
|
|
6783
9687
|
CONFIRM_JSON_SCHEMA_PROPERTIES,
|
|
@@ -6792,12 +9696,15 @@ var SqlTokenStreamSink = class {
|
|
|
6792
9696
|
DEFAULT_MAX_SKILLS,
|
|
6793
9697
|
DEFAULT_REFUSAL_REASON,
|
|
6794
9698
|
DEFAULT_STRUCTURED_OUTPUT_INSTRUCTION,
|
|
9699
|
+
DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES,
|
|
9700
|
+
DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY,
|
|
6795
9701
|
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
6796
9702
|
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
6797
9703
|
DefaultApprovalPolicy,
|
|
6798
9704
|
DefaultRolesPolicy,
|
|
6799
9705
|
ELICITATION_INPUT_TYPES,
|
|
6800
9706
|
GLOBAL_SCOPE,
|
|
9707
|
+
InMemoryActionProposalStore,
|
|
6801
9708
|
InMemoryAgentStore,
|
|
6802
9709
|
InMemoryConfirmTokenStore,
|
|
6803
9710
|
MAX_ASK_QUESTIONS,
|
|
@@ -6821,15 +9728,25 @@ var SqlTokenStreamSink = class {
|
|
|
6821
9728
|
THREAD_DETAIL_CONTENT_CHARS,
|
|
6822
9729
|
ToolDisabledError,
|
|
6823
9730
|
ToolForbiddenError,
|
|
9731
|
+
ToolInputDriftError,
|
|
6824
9732
|
ToolInputInvalidError,
|
|
6825
9733
|
ToolNotFoundError,
|
|
9734
|
+
ToolPreflightDeniedError,
|
|
6826
9735
|
ToolRegistry,
|
|
6827
9736
|
UNFINISHED_TOOL_CALL,
|
|
9737
|
+
actionProposalCreationMatches,
|
|
9738
|
+
actionProposalOutcomeFenceValid,
|
|
9739
|
+
actionProposalOutcomeScope,
|
|
9740
|
+
actionProposalOutcomeText,
|
|
9741
|
+
actionProposalReceipt,
|
|
9742
|
+
actionProposalScopeMatches,
|
|
6828
9743
|
actorScope,
|
|
6829
9744
|
agentDiagnosticKey,
|
|
6830
9745
|
agentFailureCode,
|
|
6831
9746
|
askInputSchema,
|
|
6832
9747
|
askToolDefinition,
|
|
9748
|
+
assertIndependentActionCapabilities,
|
|
9749
|
+
attachActionProposalOutcome,
|
|
6833
9750
|
bucketByActor,
|
|
6834
9751
|
bucketByModel,
|
|
6835
9752
|
bucketByThread,
|
|
@@ -6837,12 +9754,16 @@ var SqlTokenStreamSink = class {
|
|
|
6837
9754
|
buildMemoryBlock,
|
|
6838
9755
|
buildSkillsBlock,
|
|
6839
9756
|
canActorUseTool,
|
|
9757
|
+
canonicalActionProposalJson,
|
|
6840
9758
|
canonicalJson,
|
|
9759
|
+
claimActionProposalOutcome,
|
|
6841
9760
|
closeEmptyRoles,
|
|
6842
9761
|
compositeSkillProvider,
|
|
6843
9762
|
confirmTokenExpiry,
|
|
6844
9763
|
createFrameBuffer,
|
|
9764
|
+
createFunctionalTool,
|
|
6845
9765
|
createIncrementalGate,
|
|
9766
|
+
createNegotiatedUiCollector,
|
|
6846
9767
|
createNoopEmitUi,
|
|
6847
9768
|
createUiCollector,
|
|
6848
9769
|
danglingToolCallIds,
|
|
@@ -6854,7 +9775,9 @@ var SqlTokenStreamSink = class {
|
|
|
6854
9775
|
detachedDelivered,
|
|
6855
9776
|
detachedStarted,
|
|
6856
9777
|
detachedUnsettled,
|
|
9778
|
+
emitToolPresentations,
|
|
6857
9779
|
encodeStreamEvent,
|
|
9780
|
+
escapeUnsafeToolUiText,
|
|
6858
9781
|
estimateCost,
|
|
6859
9782
|
estimateMessageTokens,
|
|
6860
9783
|
exhaustedWindow,
|
|
@@ -6869,6 +9792,7 @@ var SqlTokenStreamSink = class {
|
|
|
6869
9792
|
gateFollowUps,
|
|
6870
9793
|
gateTail,
|
|
6871
9794
|
hashConfirmToken,
|
|
9795
|
+
initialActionProposal,
|
|
6872
9796
|
intersectAllowLists,
|
|
6873
9797
|
invokeWithTransientRetry,
|
|
6874
9798
|
isChatQueueStore,
|
|
@@ -6887,7 +9811,10 @@ var SqlTokenStreamSink = class {
|
|
|
6887
9811
|
observeTurnFrames,
|
|
6888
9812
|
offerMemories,
|
|
6889
9813
|
offerSkills,
|
|
9814
|
+
parseTextActionProposalCommand,
|
|
6890
9815
|
personaCatalogEntry,
|
|
9816
|
+
prepareActionProposal,
|
|
9817
|
+
ptBrActionProposalText,
|
|
6891
9818
|
publishAgentDelegated,
|
|
6892
9819
|
publishAgentMemoryResolved,
|
|
6893
9820
|
publishAgentMemoryWritten,
|
|
@@ -6913,12 +9840,14 @@ var SqlTokenStreamSink = class {
|
|
|
6913
9840
|
rememberToolDefinition,
|
|
6914
9841
|
renderElicitationAnswers,
|
|
6915
9842
|
repairInstruction,
|
|
9843
|
+
resolveActionProposalApproval,
|
|
6916
9844
|
resolveElicitation,
|
|
6917
9845
|
resolveGateLookback,
|
|
6918
9846
|
resolveMemoryDigest,
|
|
6919
9847
|
resolveOutputGateMode,
|
|
6920
9848
|
resolvePersonaAlias,
|
|
6921
9849
|
resolveSkillCatalog,
|
|
9850
|
+
resolveTextActionProposalDecision,
|
|
6922
9851
|
resolveToolTransientRetryNumbers,
|
|
6923
9852
|
rollupThreadUsage,
|
|
6924
9853
|
runAgentLoop,
|
|
@@ -6935,18 +9864,32 @@ var SqlTokenStreamSink = class {
|
|
|
6935
9864
|
skillInputSchema,
|
|
6936
9865
|
skillToolDefinition,
|
|
6937
9866
|
skillWriteVerdict,
|
|
9867
|
+
snapshotActionProposal,
|
|
6938
9868
|
stampToolKinds,
|
|
6939
9869
|
staticModelCatalog,
|
|
6940
9870
|
staticSkillProvider,
|
|
6941
9871
|
streamFailure,
|
|
6942
9872
|
summarizeWithModel,
|
|
6943
9873
|
tenantScope,
|
|
9874
|
+
textActionProposalReply,
|
|
9875
|
+
toActionProposalMutationView,
|
|
9876
|
+
toActionProposalView,
|
|
6944
9877
|
toolCallApprovalFromRow,
|
|
6945
9878
|
toolCallContext,
|
|
6946
9879
|
traceLlmTurn,
|
|
6947
9880
|
traceToolExecution,
|
|
9881
|
+
transitionActionProposalClaim,
|
|
9882
|
+
transitionActionProposalDecision,
|
|
9883
|
+
transitionActionProposalLease,
|
|
9884
|
+
transitionActionProposalSettlement,
|
|
9885
|
+
transitionActionProposalSupersession,
|
|
6948
9886
|
truncateDetailContent,
|
|
6949
9887
|
unwrapToolStepOutput,
|
|
9888
|
+
validateActionProposalCreation,
|
|
9889
|
+
validateActionProposalDiscoveryIndexBatch,
|
|
9890
|
+
validateActionProposalExpiryBatch,
|
|
9891
|
+
validateActionProposalListQuery,
|
|
9892
|
+
validateActionProposalWorkerClaim,
|
|
6950
9893
|
validateElicitationAnswer,
|
|
6951
9894
|
validateElicitationValue,
|
|
6952
9895
|
validateStructured,
|
|
@@ -6959,6 +9902,7 @@ var SqlTokenStreamSink = class {
|
|
|
6959
9902
|
withSkillTool,
|
|
6960
9903
|
withToolTimeout,
|
|
6961
9904
|
withTurnFrames,
|
|
9905
|
+
wrapToolPreflightDenied,
|
|
6962
9906
|
wrapToolStepOutput,
|
|
6963
9907
|
writeMemory
|
|
6964
9908
|
});
|