@dudousxd/nestjs-agent-core 0.38.1 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ag-ui/index.cjs +78 -0
- package/dist/ag-ui/index.cjs.map +1 -1
- package/dist/ag-ui/index.d.cts +12 -2
- package/dist/ag-ui/index.d.ts +12 -2
- package/dist/ag-ui/index.js +77 -0
- package/dist/ag-ui/index.js.map +1 -1
- package/dist/genui/builtins.cjs +2 -0
- package/dist/genui/builtins.cjs.map +1 -1
- package/dist/genui/builtins.js +2 -0
- package/dist/genui/builtins.js.map +1 -1
- package/dist/genui/index.cjs +120 -38
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.d.cts +2 -2
- package/dist/genui/index.d.ts +2 -2
- package/dist/genui/index.js +116 -37
- package/dist/genui/index.js.map +1 -1
- package/dist/guardrails/index.d.cts +3 -3
- package/dist/guardrails/index.d.ts +3 -3
- package/dist/index.cjs +2524 -148
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +321 -95
- package/dist/index.d.ts +321 -95
- package/dist/index.js +2482 -144
- package/dist/index.js.map +1 -1
- package/dist/{processors-CAVevaYJ.d.cts → processors-B7nfbU6E.d.cts} +3 -1
- package/dist/{processors-C-FP4nDy.d.ts → processors-BR3nICcp.d.ts} +3 -1
- package/dist/{stream-events-rpd3d6gh.d.cts → stream-events-DAmes2Of.d.ts} +704 -86
- package/dist/{stream-events-rpd3d6gh.d.ts → stream-events-M0jc7lSW.d.cts} +704 -86
- package/package.json +1 -1
- package/dist/tool-Dp8HA_f4.d.cts +0 -119
- package/dist/tool-hhssZ_HW.d.ts +0 -119
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,
|
|
@@ -73,6 +75,7 @@ __export(src_exports, {
|
|
|
73
75
|
DefaultRolesPolicy: () => DefaultRolesPolicy,
|
|
74
76
|
ELICITATION_INPUT_TYPES: () => ELICITATION_INPUT_TYPES,
|
|
75
77
|
GLOBAL_SCOPE: () => GLOBAL_SCOPE,
|
|
78
|
+
InMemoryActionProposalStore: () => InMemoryActionProposalStore,
|
|
76
79
|
InMemoryAgentStore: () => InMemoryAgentStore,
|
|
77
80
|
InMemoryConfirmTokenStore: () => InMemoryConfirmTokenStore,
|
|
78
81
|
MAX_ASK_QUESTIONS: () => MAX_ASK_QUESTIONS,
|
|
@@ -96,15 +99,25 @@ __export(src_exports, {
|
|
|
96
99
|
THREAD_DETAIL_CONTENT_CHARS: () => THREAD_DETAIL_CONTENT_CHARS,
|
|
97
100
|
ToolDisabledError: () => ToolDisabledError,
|
|
98
101
|
ToolForbiddenError: () => ToolForbiddenError,
|
|
102
|
+
ToolInputDriftError: () => ToolInputDriftError,
|
|
99
103
|
ToolInputInvalidError: () => ToolInputInvalidError,
|
|
100
104
|
ToolNotFoundError: () => ToolNotFoundError,
|
|
105
|
+
ToolPreflightDeniedError: () => ToolPreflightDeniedError,
|
|
101
106
|
ToolRegistry: () => ToolRegistry,
|
|
102
107
|
UNFINISHED_TOOL_CALL: () => UNFINISHED_TOOL_CALL,
|
|
108
|
+
actionProposalCreationMatches: () => actionProposalCreationMatches,
|
|
109
|
+
actionProposalOutcomeFenceValid: () => actionProposalOutcomeFenceValid,
|
|
110
|
+
actionProposalOutcomeScope: () => actionProposalOutcomeScope,
|
|
111
|
+
actionProposalOutcomeText: () => actionProposalOutcomeText,
|
|
112
|
+
actionProposalReceipt: () => actionProposalReceipt,
|
|
113
|
+
actionProposalScopeMatches: () => actionProposalScopeMatches,
|
|
103
114
|
actorScope: () => actorScope,
|
|
104
115
|
agentDiagnosticKey: () => agentDiagnosticKey,
|
|
105
116
|
agentFailureCode: () => agentFailureCode,
|
|
106
117
|
askInputSchema: () => askInputSchema,
|
|
107
118
|
askToolDefinition: () => askToolDefinition,
|
|
119
|
+
assertIndependentActionCapabilities: () => assertIndependentActionCapabilities,
|
|
120
|
+
attachActionProposalOutcome: () => attachActionProposalOutcome,
|
|
108
121
|
bucketByActor: () => bucketByActor,
|
|
109
122
|
bucketByModel: () => bucketByModel,
|
|
110
123
|
bucketByThread: () => bucketByThread,
|
|
@@ -112,12 +125,15 @@ __export(src_exports, {
|
|
|
112
125
|
buildMemoryBlock: () => buildMemoryBlock,
|
|
113
126
|
buildSkillsBlock: () => buildSkillsBlock,
|
|
114
127
|
canActorUseTool: () => canActorUseTool,
|
|
128
|
+
canonicalActionProposalJson: () => canonicalActionProposalJson,
|
|
115
129
|
canonicalJson: () => canonicalJson,
|
|
130
|
+
claimActionProposalOutcome: () => claimActionProposalOutcome,
|
|
116
131
|
closeEmptyRoles: () => closeEmptyRoles,
|
|
117
132
|
compositeSkillProvider: () => compositeSkillProvider,
|
|
118
133
|
confirmTokenExpiry: () => confirmTokenExpiry,
|
|
119
134
|
createFrameBuffer: () => createFrameBuffer,
|
|
120
135
|
createIncrementalGate: () => createIncrementalGate,
|
|
136
|
+
createNegotiatedUiCollector: () => createNegotiatedUiCollector,
|
|
121
137
|
createNoopEmitUi: () => createNoopEmitUi,
|
|
122
138
|
createUiCollector: () => createUiCollector,
|
|
123
139
|
danglingToolCallIds: () => danglingToolCallIds,
|
|
@@ -130,6 +146,7 @@ __export(src_exports, {
|
|
|
130
146
|
detachedStarted: () => detachedStarted,
|
|
131
147
|
detachedUnsettled: () => detachedUnsettled,
|
|
132
148
|
encodeStreamEvent: () => encodeStreamEvent,
|
|
149
|
+
escapeUnsafeToolUiText: () => escapeUnsafeToolUiText,
|
|
133
150
|
estimateCost: () => estimateCost,
|
|
134
151
|
estimateMessageTokens: () => estimateMessageTokens,
|
|
135
152
|
exhaustedWindow: () => exhaustedWindow,
|
|
@@ -140,9 +157,12 @@ __export(src_exports, {
|
|
|
140
157
|
filterToolsByEnabled: () => filterToolsByEnabled,
|
|
141
158
|
filterToolsByRole: () => filterToolsByRole,
|
|
142
159
|
findCatalogModel: () => findCatalogModel,
|
|
160
|
+
findPersona: () => findPersona,
|
|
143
161
|
gateFollowUps: () => gateFollowUps,
|
|
144
162
|
gateTail: () => gateTail,
|
|
145
163
|
hashConfirmToken: () => hashConfirmToken,
|
|
164
|
+
initialActionProposal: () => initialActionProposal,
|
|
165
|
+
intersectAllowLists: () => intersectAllowLists,
|
|
146
166
|
invokeWithTransientRetry: () => invokeWithTransientRetry,
|
|
147
167
|
isChatQueueStore: () => isChatQueueStore,
|
|
148
168
|
isControlFlowSignal: () => isControlFlowSignal,
|
|
@@ -160,6 +180,9 @@ __export(src_exports, {
|
|
|
160
180
|
observeTurnFrames: () => observeTurnFrames,
|
|
161
181
|
offerMemories: () => offerMemories,
|
|
162
182
|
offerSkills: () => offerSkills,
|
|
183
|
+
parseTextActionProposalCommand: () => parseTextActionProposalCommand,
|
|
184
|
+
personaCatalogEntry: () => personaCatalogEntry,
|
|
185
|
+
prepareActionProposal: () => prepareActionProposal,
|
|
163
186
|
publishAgentDelegated: () => publishAgentDelegated,
|
|
164
187
|
publishAgentMemoryResolved: () => publishAgentMemoryResolved,
|
|
165
188
|
publishAgentMemoryWritten: () => publishAgentMemoryWritten,
|
|
@@ -185,11 +208,14 @@ __export(src_exports, {
|
|
|
185
208
|
rememberToolDefinition: () => rememberToolDefinition,
|
|
186
209
|
renderElicitationAnswers: () => renderElicitationAnswers,
|
|
187
210
|
repairInstruction: () => repairInstruction,
|
|
211
|
+
resolveActionProposalApproval: () => resolveActionProposalApproval,
|
|
188
212
|
resolveElicitation: () => resolveElicitation,
|
|
189
213
|
resolveGateLookback: () => resolveGateLookback,
|
|
190
214
|
resolveMemoryDigest: () => resolveMemoryDigest,
|
|
191
215
|
resolveOutputGateMode: () => resolveOutputGateMode,
|
|
216
|
+
resolvePersonaAlias: () => resolvePersonaAlias,
|
|
192
217
|
resolveSkillCatalog: () => resolveSkillCatalog,
|
|
218
|
+
resolveTextActionProposalDecision: () => resolveTextActionProposalDecision,
|
|
193
219
|
resolveToolTransientRetryNumbers: () => resolveToolTransientRetryNumbers,
|
|
194
220
|
rollupThreadUsage: () => rollupThreadUsage,
|
|
195
221
|
runAgentLoop: () => runAgentLoop,
|
|
@@ -206,6 +232,7 @@ __export(src_exports, {
|
|
|
206
232
|
skillInputSchema: () => skillInputSchema,
|
|
207
233
|
skillToolDefinition: () => skillToolDefinition,
|
|
208
234
|
skillWriteVerdict: () => skillWriteVerdict,
|
|
235
|
+
snapshotActionProposal: () => snapshotActionProposal,
|
|
209
236
|
stampToolKinds: () => stampToolKinds,
|
|
210
237
|
staticModelCatalog: () => staticModelCatalog,
|
|
211
238
|
staticSkillProvider: () => staticSkillProvider,
|
|
@@ -216,8 +243,18 @@ __export(src_exports, {
|
|
|
216
243
|
toolCallContext: () => toolCallContext,
|
|
217
244
|
traceLlmTurn: () => traceLlmTurn,
|
|
218
245
|
traceToolExecution: () => traceToolExecution,
|
|
246
|
+
transitionActionProposalClaim: () => transitionActionProposalClaim,
|
|
247
|
+
transitionActionProposalDecision: () => transitionActionProposalDecision,
|
|
248
|
+
transitionActionProposalLease: () => transitionActionProposalLease,
|
|
249
|
+
transitionActionProposalSettlement: () => transitionActionProposalSettlement,
|
|
250
|
+
transitionActionProposalSupersession: () => transitionActionProposalSupersession,
|
|
219
251
|
truncateDetailContent: () => truncateDetailContent,
|
|
220
252
|
unwrapToolStepOutput: () => unwrapToolStepOutput,
|
|
253
|
+
validateActionProposalCreation: () => validateActionProposalCreation,
|
|
254
|
+
validateActionProposalDiscoveryIndexBatch: () => validateActionProposalDiscoveryIndexBatch,
|
|
255
|
+
validateActionProposalExpiryBatch: () => validateActionProposalExpiryBatch,
|
|
256
|
+
validateActionProposalListQuery: () => validateActionProposalListQuery,
|
|
257
|
+
validateActionProposalWorkerClaim: () => validateActionProposalWorkerClaim,
|
|
221
258
|
validateElicitationAnswer: () => validateElicitationAnswer,
|
|
222
259
|
validateElicitationValue: () => validateElicitationValue,
|
|
223
260
|
validateStructured: () => validateStructured,
|
|
@@ -230,6 +267,7 @@ __export(src_exports, {
|
|
|
230
267
|
withSkillTool: () => withSkillTool,
|
|
231
268
|
withToolTimeout: () => withToolTimeout,
|
|
232
269
|
withTurnFrames: () => withTurnFrames,
|
|
270
|
+
wrapToolPreflightDenied: () => wrapToolPreflightDenied,
|
|
233
271
|
wrapToolStepOutput: () => wrapToolStepOutput,
|
|
234
272
|
writeMemory: () => writeMemory
|
|
235
273
|
});
|
|
@@ -403,16 +441,16 @@ function observeTurnFrames(writer, now = Date.now) {
|
|
|
403
441
|
};
|
|
404
442
|
}
|
|
405
443
|
__name(observeTurnFrames, "observeTurnFrames");
|
|
406
|
-
function withTurnFrames(
|
|
444
|
+
function withTurnFrames(result2, frames) {
|
|
407
445
|
return {
|
|
408
|
-
...
|
|
409
|
-
...
|
|
446
|
+
...result2,
|
|
447
|
+
...result2.reasoning === void 0 && frames.reasoning !== void 0 ? {
|
|
410
448
|
reasoning: frames.reasoning
|
|
411
449
|
} : {},
|
|
412
|
-
...
|
|
450
|
+
...result2.reasoningMs === void 0 && frames.reasoningMs !== void 0 ? {
|
|
413
451
|
reasoningMs: frames.reasoningMs
|
|
414
452
|
} : {},
|
|
415
|
-
...
|
|
453
|
+
...result2.ui === void 0 && frames.ui !== void 0 ? {
|
|
416
454
|
ui: frames.ui
|
|
417
455
|
} : {}
|
|
418
456
|
};
|
|
@@ -421,8 +459,9 @@ __name(withTurnFrames, "withTurnFrames");
|
|
|
421
459
|
|
|
422
460
|
// src/tool-ui.ts
|
|
423
461
|
var TOOL_STEP_UI = "@@nestjs-agent/tool-step-ui";
|
|
424
|
-
function wrapToolStepOutput(output, ui) {
|
|
425
|
-
|
|
462
|
+
function wrapToolStepOutput(output, ui, text) {
|
|
463
|
+
const reserved = typeof output === "object" && output !== null && TOOL_STEP_UI in output;
|
|
464
|
+
if (ui.length === 0 && !reserved && !text) {
|
|
426
465
|
return output;
|
|
427
466
|
}
|
|
428
467
|
const wrapped = {
|
|
@@ -430,17 +469,36 @@ function wrapToolStepOutput(output, ui) {
|
|
|
430
469
|
output,
|
|
431
470
|
ui: [
|
|
432
471
|
...ui
|
|
433
|
-
]
|
|
472
|
+
],
|
|
473
|
+
...text ? {
|
|
474
|
+
text
|
|
475
|
+
} : {}
|
|
434
476
|
};
|
|
435
477
|
return wrapped;
|
|
436
478
|
}
|
|
437
479
|
__name(wrapToolStepOutput, "wrapToolStepOutput");
|
|
480
|
+
function wrapToolPreflightDenied(reason) {
|
|
481
|
+
const wrapped = {
|
|
482
|
+
[TOOL_STEP_UI]: 1,
|
|
483
|
+
output: null,
|
|
484
|
+
ui: [],
|
|
485
|
+
preflightDenied: reason
|
|
486
|
+
};
|
|
487
|
+
return wrapped;
|
|
488
|
+
}
|
|
489
|
+
__name(wrapToolPreflightDenied, "wrapToolPreflightDenied");
|
|
438
490
|
function unwrapToolStepOutput(raw) {
|
|
439
491
|
if (typeof raw === "object" && raw !== null && raw[TOOL_STEP_UI] === 1) {
|
|
440
492
|
const wrapped = raw;
|
|
441
493
|
return {
|
|
442
494
|
output: wrapped.output,
|
|
443
|
-
ui: Array.isArray(wrapped.ui) ? wrapped.ui : []
|
|
495
|
+
ui: Array.isArray(wrapped.ui) ? wrapped.ui : [],
|
|
496
|
+
...typeof wrapped.text === "string" ? {
|
|
497
|
+
text: wrapped.text
|
|
498
|
+
} : {},
|
|
499
|
+
...typeof wrapped.preflightDenied === "string" ? {
|
|
500
|
+
preflightDenied: wrapped.preflightDenied
|
|
501
|
+
} : {}
|
|
444
502
|
};
|
|
445
503
|
}
|
|
446
504
|
return {
|
|
@@ -489,6 +547,14 @@ function createUiCollector(toolCallId, write) {
|
|
|
489
547
|
...options.version !== void 0 ? {
|
|
490
548
|
version: options.version
|
|
491
549
|
} : {},
|
|
550
|
+
...options.fallbackText !== void 0 ? {
|
|
551
|
+
fallbackText: options.fallbackText
|
|
552
|
+
} : {},
|
|
553
|
+
...options.componentVersions !== void 0 ? {
|
|
554
|
+
componentVersions: {
|
|
555
|
+
...options.componentVersions
|
|
556
|
+
}
|
|
557
|
+
} : {},
|
|
492
558
|
toolCallId
|
|
493
559
|
};
|
|
494
560
|
pushed.set(id, entry);
|
|
@@ -523,6 +589,10 @@ function mergeUi(...lists) {
|
|
|
523
589
|
];
|
|
524
590
|
}
|
|
525
591
|
__name(mergeUi, "mergeUi");
|
|
592
|
+
function escapeUnsafeToolUiText(text) {
|
|
593
|
+
return text.replaceAll("\0", "\\u0000").replace(/[\uD800-\uDFFF]/gu, (unit) => `\\u${unit.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
594
|
+
}
|
|
595
|
+
__name(escapeUnsafeToolUiText, "escapeUnsafeToolUiText");
|
|
526
596
|
|
|
527
597
|
// src/tool-presentation.ts
|
|
528
598
|
var ALL_AGENTS = "*";
|
|
@@ -565,6 +635,9 @@ function queuedMessageView(message) {
|
|
|
565
635
|
...message.agentName !== void 0 ? {
|
|
566
636
|
agentName: message.agentName
|
|
567
637
|
} : {},
|
|
638
|
+
...message.persona !== void 0 ? {
|
|
639
|
+
persona: message.persona
|
|
640
|
+
} : {},
|
|
568
641
|
...message.model !== void 0 ? {
|
|
569
642
|
model: message.model
|
|
570
643
|
} : {},
|
|
@@ -731,12 +804,18 @@ function toolCallApprovalFromRow(row) {
|
|
|
731
804
|
if (row.approver === null || row.approver === void 0) {
|
|
732
805
|
return null;
|
|
733
806
|
}
|
|
734
|
-
const status = row.status === "pending_approval" ? "pending" : row.status === "rejected" ? "rejected" : row.status === "expired" ? "expired" : "approved";
|
|
807
|
+
const status = row.status === "pending_approval" || row.status === "proposed" ? "pending" : row.status === "rejected" ? "rejected" : row.status === "expired" ? "expired" : "approved";
|
|
735
808
|
const expiresAt = row.expiresAt instanceof Date ? row.expiresAt.toISOString() : typeof row.expiresAt === "string" ? row.expiresAt : void 0;
|
|
736
809
|
const decided = status === "approved" || status === "rejected";
|
|
737
810
|
return {
|
|
738
811
|
toolCallId: row.toolCallId,
|
|
812
|
+
...row.proposalId != null ? {
|
|
813
|
+
proposalId: row.proposalId
|
|
814
|
+
} : {},
|
|
739
815
|
approver: row.approver,
|
|
816
|
+
...row.confirmation != null ? {
|
|
817
|
+
confirmation: row.confirmation
|
|
818
|
+
} : {},
|
|
740
819
|
status,
|
|
741
820
|
...expiresAt !== void 0 ? {
|
|
742
821
|
expiresAt
|
|
@@ -787,9 +866,9 @@ function bucketByModel(rows, prices) {
|
|
|
787
866
|
bucket.costUsd += rowCost(row, prices);
|
|
788
867
|
byModel.set(row.modelId, bucket);
|
|
789
868
|
}
|
|
790
|
-
const
|
|
869
|
+
const result2 = [];
|
|
791
870
|
for (const [modelId, bucket] of byModel) {
|
|
792
|
-
|
|
871
|
+
result2.push({
|
|
793
872
|
modelId,
|
|
794
873
|
requests: bucket.requests,
|
|
795
874
|
inputTokens: bucket.inputTokens,
|
|
@@ -797,8 +876,8 @@ function bucketByModel(rows, prices) {
|
|
|
797
876
|
costUsd: bucket.costUsd
|
|
798
877
|
});
|
|
799
878
|
}
|
|
800
|
-
|
|
801
|
-
return
|
|
879
|
+
result2.sort((left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId));
|
|
880
|
+
return result2;
|
|
802
881
|
}
|
|
803
882
|
__name(bucketByModel, "bucketByModel");
|
|
804
883
|
function bucketByActor(rows, prices) {
|
|
@@ -816,9 +895,9 @@ function bucketByActor(rows, prices) {
|
|
|
816
895
|
bucket.threadIds.add(row.threadId);
|
|
817
896
|
byActor.set(row.actorRef, bucket);
|
|
818
897
|
}
|
|
819
|
-
const
|
|
898
|
+
const result2 = [];
|
|
820
899
|
for (const [actorRef, bucket] of byActor) {
|
|
821
|
-
|
|
900
|
+
result2.push({
|
|
822
901
|
actorRef,
|
|
823
902
|
requests: bucket.requests,
|
|
824
903
|
totalTokens: bucket.totalTokens,
|
|
@@ -826,8 +905,8 @@ function bucketByActor(rows, prices) {
|
|
|
826
905
|
threadCount: bucket.threadIds.size
|
|
827
906
|
});
|
|
828
907
|
}
|
|
829
|
-
|
|
830
|
-
return
|
|
908
|
+
result2.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
|
|
909
|
+
return result2;
|
|
831
910
|
}
|
|
832
911
|
__name(bucketByActor, "bucketByActor");
|
|
833
912
|
function bucketByThread(rows, prices, threads, options) {
|
|
@@ -843,13 +922,13 @@ function bucketByThread(rows, prices, threads, options) {
|
|
|
843
922
|
bucket.costUsd += rowCost(row, prices);
|
|
844
923
|
byThread.set(row.threadId, bucket);
|
|
845
924
|
}
|
|
846
|
-
const
|
|
925
|
+
const result2 = [];
|
|
847
926
|
for (const [threadId, bucket] of byThread) {
|
|
848
927
|
const thread = threads.get(threadId);
|
|
849
928
|
if (thread === void 0 && !options.includeUnknownThreads) {
|
|
850
929
|
continue;
|
|
851
930
|
}
|
|
852
|
-
|
|
931
|
+
result2.push({
|
|
853
932
|
threadId,
|
|
854
933
|
title: thread?.title ?? "",
|
|
855
934
|
actorRef: thread?.actorRef ?? "",
|
|
@@ -858,8 +937,8 @@ function bucketByThread(rows, prices, threads, options) {
|
|
|
858
937
|
costUsd: bucket.costUsd
|
|
859
938
|
});
|
|
860
939
|
}
|
|
861
|
-
|
|
862
|
-
return
|
|
940
|
+
result2.sort((left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId));
|
|
941
|
+
return result2.slice(0, options.limit);
|
|
863
942
|
}
|
|
864
943
|
__name(bucketByThread, "bucketByThread");
|
|
865
944
|
function rollupThreadUsage(rows, prices) {
|
|
@@ -891,16 +970,16 @@ function bucketUsageTrend(rows, prices) {
|
|
|
891
970
|
bucket.costUsd += rowCost(row, prices);
|
|
892
971
|
byDay.set(row.day, bucket);
|
|
893
972
|
}
|
|
894
|
-
const
|
|
973
|
+
const result2 = [];
|
|
895
974
|
for (const [day, bucket] of byDay) {
|
|
896
|
-
|
|
975
|
+
result2.push({
|
|
897
976
|
day,
|
|
898
977
|
totalTokens: bucket.totalTokens,
|
|
899
978
|
costUsd: bucket.costUsd
|
|
900
979
|
});
|
|
901
980
|
}
|
|
902
|
-
|
|
903
|
-
return
|
|
981
|
+
result2.sort((left, right) => left.day.localeCompare(right.day));
|
|
982
|
+
return result2;
|
|
904
983
|
}
|
|
905
984
|
__name(bucketUsageTrend, "bucketUsageTrend");
|
|
906
985
|
function dayBoundsUtc(range) {
|
|
@@ -957,6 +1036,54 @@ function filterToolsByAllowList(tools, allowedTools) {
|
|
|
957
1036
|
}
|
|
958
1037
|
__name(filterToolsByAllowList, "filterToolsByAllowList");
|
|
959
1038
|
|
|
1039
|
+
// src/personas.ts
|
|
1040
|
+
function intersectAllowLists(first, second) {
|
|
1041
|
+
if (first === void 0) {
|
|
1042
|
+
return second === void 0 ? void 0 : [
|
|
1043
|
+
...second
|
|
1044
|
+
];
|
|
1045
|
+
}
|
|
1046
|
+
if (second === void 0) {
|
|
1047
|
+
return [
|
|
1048
|
+
...first
|
|
1049
|
+
];
|
|
1050
|
+
}
|
|
1051
|
+
const allowed = new Set(second);
|
|
1052
|
+
return first.filter((name) => allowed.has(name));
|
|
1053
|
+
}
|
|
1054
|
+
__name(intersectAllowLists, "intersectAllowLists");
|
|
1055
|
+
function findPersona(definition, id) {
|
|
1056
|
+
if (id === void 0) {
|
|
1057
|
+
return void 0;
|
|
1058
|
+
}
|
|
1059
|
+
return definition?.personas?.find((persona) => persona.id === id);
|
|
1060
|
+
}
|
|
1061
|
+
__name(findPersona, "findPersona");
|
|
1062
|
+
function personaCatalogEntry(persona) {
|
|
1063
|
+
return {
|
|
1064
|
+
id: persona.id,
|
|
1065
|
+
label: persona.label,
|
|
1066
|
+
...persona.description !== void 0 ? {
|
|
1067
|
+
description: persona.description
|
|
1068
|
+
} : {}
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
__name(personaCatalogEntry, "personaCatalogEntry");
|
|
1072
|
+
function resolvePersonaAlias(definitions, name) {
|
|
1073
|
+
for (const definition of definitions) {
|
|
1074
|
+
for (const persona of definition.personas ?? []) {
|
|
1075
|
+
if (persona.aliases?.includes(name) === true) {
|
|
1076
|
+
return {
|
|
1077
|
+
agent: definition.name,
|
|
1078
|
+
persona: persona.id
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
return void 0;
|
|
1084
|
+
}
|
|
1085
|
+
__name(resolvePersonaAlias, "resolvePersonaAlias");
|
|
1086
|
+
|
|
960
1087
|
// src/history.ts
|
|
961
1088
|
function estimateMessageTokens(message) {
|
|
962
1089
|
const extras = (message.toolCalls !== void 0 ? JSON.stringify(message.toolCalls).length : 0) + (message.toolResults !== void 0 ? JSON.stringify(message.toolResults).length : 0);
|
|
@@ -1296,13 +1423,13 @@ async function validateStructured(schema, text, reported) {
|
|
|
1296
1423
|
issues: []
|
|
1297
1424
|
};
|
|
1298
1425
|
}
|
|
1299
|
-
const
|
|
1300
|
-
return
|
|
1426
|
+
const result2 = await schema["~standard"].validate(candidate);
|
|
1427
|
+
return result2.issues !== void 0 ? {
|
|
1301
1428
|
ok: false,
|
|
1302
|
-
issues:
|
|
1429
|
+
issues: result2.issues
|
|
1303
1430
|
} : {
|
|
1304
1431
|
ok: true,
|
|
1305
|
-
value:
|
|
1432
|
+
value: result2.value
|
|
1306
1433
|
};
|
|
1307
1434
|
}
|
|
1308
1435
|
__name(validateStructured, "validateStructured");
|
|
@@ -2481,12 +2608,12 @@ function memoryWriteVerdict(request) {
|
|
|
2481
2608
|
};
|
|
2482
2609
|
}
|
|
2483
2610
|
__name(memoryWriteVerdict, "memoryWriteVerdict");
|
|
2484
|
-
function memoryForgetVerdict({ record, actor }) {
|
|
2485
|
-
return
|
|
2611
|
+
function memoryForgetVerdict({ record: record2, actor }) {
|
|
2612
|
+
return record2.scope === actorScope(actor) ? {
|
|
2486
2613
|
allowed: true
|
|
2487
2614
|
} : {
|
|
2488
2615
|
allowed: false,
|
|
2489
|
-
reason: `"${
|
|
2616
|
+
reason: `"${record2.scope}" is not this actor's own scope; deleting it is an administrative action`
|
|
2490
2617
|
};
|
|
2491
2618
|
}
|
|
2492
2619
|
__name(memoryForgetVerdict, "memoryForgetVerdict");
|
|
@@ -2529,7 +2656,7 @@ async function writeMemory({ config, digest, call, ctx, runId }) {
|
|
|
2529
2656
|
error: verdict.reason
|
|
2530
2657
|
};
|
|
2531
2658
|
}
|
|
2532
|
-
const
|
|
2659
|
+
const record2 = await write({
|
|
2533
2660
|
key,
|
|
2534
2661
|
text,
|
|
2535
2662
|
scope,
|
|
@@ -2543,7 +2670,7 @@ async function writeMemory({ config, digest, call, ctx, runId }) {
|
|
|
2543
2670
|
});
|
|
2544
2671
|
return {
|
|
2545
2672
|
ok: true,
|
|
2546
|
-
record
|
|
2673
|
+
record: record2
|
|
2547
2674
|
};
|
|
2548
2675
|
}
|
|
2549
2676
|
__name(writeMemory, "writeMemory");
|
|
@@ -2595,7 +2722,7 @@ function danglingToolCallIds(messages) {
|
|
|
2595
2722
|
if (message.role !== "assistant" || calls.length === 0) {
|
|
2596
2723
|
continue;
|
|
2597
2724
|
}
|
|
2598
|
-
const settled = new Set((message.toolResults ?? []).map((
|
|
2725
|
+
const settled = new Set((message.toolResults ?? []).map((result2) => result2.id));
|
|
2599
2726
|
for (const call of calls) {
|
|
2600
2727
|
if (!settled.has(call.id)) {
|
|
2601
2728
|
ids.push(call.id);
|
|
@@ -2663,7 +2790,7 @@ function settleDanglingToolCalls(messages, outcomes = []) {
|
|
|
2663
2790
|
return message;
|
|
2664
2791
|
}
|
|
2665
2792
|
const results = message.toolResults ?? [];
|
|
2666
|
-
const settled = new Set(results.map((
|
|
2793
|
+
const settled = new Set(results.map((result2) => result2.id));
|
|
2667
2794
|
const missing = calls.filter((call) => !settled.has(call.id));
|
|
2668
2795
|
if (missing.length === 0) {
|
|
2669
2796
|
return message;
|
|
@@ -2771,6 +2898,1111 @@ async function settleUnsettledDelegation(args) {
|
|
|
2771
2898
|
}
|
|
2772
2899
|
__name(settleUnsettledDelegation, "settleUnsettledDelegation");
|
|
2773
2900
|
|
|
2901
|
+
// src/action-proposal-discovery.ts
|
|
2902
|
+
function validateActionProposalWorkerClaim(command, now) {
|
|
2903
|
+
if (!Number.isSafeInteger(now)) throw new RangeError("Invalid action proposal clock");
|
|
2904
|
+
if (typeof command.workerId !== "string" || command.workerId.length === 0) throw new TypeError("workerId must be a nonempty string");
|
|
2905
|
+
if (!Number.isSafeInteger(command.leaseMs) || command.leaseMs <= 0 || !Number.isSafeInteger(now + command.leaseMs)) throw new RangeError("leaseMs must be positive safe integer milliseconds");
|
|
2906
|
+
}
|
|
2907
|
+
__name(validateActionProposalWorkerClaim, "validateActionProposalWorkerClaim");
|
|
2908
|
+
function validateActionProposalExpiryBatch(command, now) {
|
|
2909
|
+
if (!Number.isSafeInteger(now)) throw new RangeError("Invalid action proposal clock");
|
|
2910
|
+
validateActionProposalDiscoveryIndexBatch(command);
|
|
2911
|
+
}
|
|
2912
|
+
__name(validateActionProposalExpiryBatch, "validateActionProposalExpiryBatch");
|
|
2913
|
+
function validateActionProposalDiscoveryIndexBatch(command) {
|
|
2914
|
+
if (!Number.isInteger(command.limit) || command.limit < 1 || command.limit > 1e3) throw new RangeError("limit must be an integer from 1 to 1000");
|
|
2915
|
+
}
|
|
2916
|
+
__name(validateActionProposalDiscoveryIndexBatch, "validateActionProposalDiscoveryIndexBatch");
|
|
2917
|
+
|
|
2918
|
+
// src/action-proposal-outcome.ts
|
|
2919
|
+
function attachActionProposalOutcome(row, now, ui = [], text) {
|
|
2920
|
+
if (row.outcome) return row;
|
|
2921
|
+
const execution = row.execution;
|
|
2922
|
+
const outcome = {
|
|
2923
|
+
id: `${row.id}:outcome:1`,
|
|
2924
|
+
proposalId: row.id,
|
|
2925
|
+
outcomeVersion: 1,
|
|
2926
|
+
tenantRef: row.tenantRef,
|
|
2927
|
+
actorRef: row.actorRef,
|
|
2928
|
+
threadId: row.threadId,
|
|
2929
|
+
originRunId: row.originRunId,
|
|
2930
|
+
originToolCallId: row.originToolCallId,
|
|
2931
|
+
toolName: row.toolName,
|
|
2932
|
+
decision: row.decision,
|
|
2933
|
+
ui,
|
|
2934
|
+
createdAt: now,
|
|
2935
|
+
...text !== void 0 ? {
|
|
2936
|
+
text
|
|
2937
|
+
} : {},
|
|
2938
|
+
...execution?.status === "succeeded" || execution?.status === "failed" ? {
|
|
2939
|
+
executionStatus: execution.status
|
|
2940
|
+
} : {},
|
|
2941
|
+
...execution && Object.hasOwn(execution, "result") ? {
|
|
2942
|
+
result: execution.result
|
|
2943
|
+
} : {},
|
|
2944
|
+
...execution?.error !== void 0 ? {
|
|
2945
|
+
error: execution.error
|
|
2946
|
+
} : row.decisionAudit?.reason !== void 0 ? {
|
|
2947
|
+
error: row.decisionAudit.reason
|
|
2948
|
+
} : {}
|
|
2949
|
+
};
|
|
2950
|
+
return snapshotActionProposal({
|
|
2951
|
+
...row,
|
|
2952
|
+
outcome,
|
|
2953
|
+
outcomeDelivery: {
|
|
2954
|
+
status: "pending",
|
|
2955
|
+
generation: 0,
|
|
2956
|
+
lease: null
|
|
2957
|
+
}
|
|
2958
|
+
});
|
|
2959
|
+
}
|
|
2960
|
+
__name(attachActionProposalOutcome, "attachActionProposalOutcome");
|
|
2961
|
+
function claimActionProposalOutcome(row, command, now, token) {
|
|
2962
|
+
validateActionProposalWorkerClaim(command, now);
|
|
2963
|
+
const delivery = row.outcomeDelivery;
|
|
2964
|
+
if (!row.outcome || !delivery || delivery.status !== "pending" || delivery.lease && now < delivery.lease.expiresAt) return null;
|
|
2965
|
+
const generation = delivery.generation + 1;
|
|
2966
|
+
return snapshotActionProposal({
|
|
2967
|
+
...row,
|
|
2968
|
+
outcomeDelivery: {
|
|
2969
|
+
...delivery,
|
|
2970
|
+
generation,
|
|
2971
|
+
lease: {
|
|
2972
|
+
token,
|
|
2973
|
+
generation,
|
|
2974
|
+
workerId: command.workerId,
|
|
2975
|
+
expiresAt: now + command.leaseMs
|
|
2976
|
+
}
|
|
2977
|
+
}
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2980
|
+
__name(claimActionProposalOutcome, "claimActionProposalOutcome");
|
|
2981
|
+
function actionProposalOutcomeFenceValid(row, command, now) {
|
|
2982
|
+
if (!Number.isSafeInteger(now)) throw new RangeError("Invalid server clock");
|
|
2983
|
+
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");
|
|
2984
|
+
const delivery = row.outcomeDelivery;
|
|
2985
|
+
return row.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;
|
|
2986
|
+
}
|
|
2987
|
+
__name(actionProposalOutcomeFenceValid, "actionProposalOutcomeFenceValid");
|
|
2988
|
+
function outcomeSummary(outcome) {
|
|
2989
|
+
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)}` : ""}`;
|
|
2990
|
+
if (outcome.executionStatus === "failed") return `Action ${JSON.stringify(outcome.toolName)} failed (proposal ${JSON.stringify(outcome.proposalId)}): ${JSON.stringify(outcome.error ?? "Execution failed")}`;
|
|
2991
|
+
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)}` : ""}`;
|
|
2992
|
+
}
|
|
2993
|
+
__name(outcomeSummary, "outcomeSummary");
|
|
2994
|
+
function actionProposalOutcomeScope(outcome) {
|
|
2995
|
+
return {
|
|
2996
|
+
tenantRef: outcome.tenantRef,
|
|
2997
|
+
actorRef: outcome.actorRef,
|
|
2998
|
+
threadId: outcome.threadId
|
|
2999
|
+
};
|
|
3000
|
+
}
|
|
3001
|
+
__name(actionProposalOutcomeScope, "actionProposalOutcomeScope");
|
|
3002
|
+
function actionProposalOutcomeText(outcome) {
|
|
3003
|
+
return outcomeSummary(outcome) + (outcome.text ? ` UI: ${JSON.stringify(outcome.text)}` : "");
|
|
3004
|
+
}
|
|
3005
|
+
__name(actionProposalOutcomeText, "actionProposalOutcomeText");
|
|
3006
|
+
|
|
3007
|
+
// src/genui/schema.ts
|
|
3008
|
+
function isStandardSchema(schema) {
|
|
3009
|
+
return typeof schema === "object" && schema !== null && "~standard" in schema && typeof schema["~standard"]?.validate === "function";
|
|
3010
|
+
}
|
|
3011
|
+
__name(isStandardSchema, "isStandardSchema");
|
|
3012
|
+
function toJsonSchema(schema) {
|
|
3013
|
+
if (!isStandardSchema(schema)) {
|
|
3014
|
+
return schema;
|
|
3015
|
+
}
|
|
3016
|
+
const standard = schema["~standard"];
|
|
3017
|
+
const converter = standard.jsonSchema;
|
|
3018
|
+
if (converter === void 0 || typeof converter.input !== "function") {
|
|
3019
|
+
return void 0;
|
|
3020
|
+
}
|
|
3021
|
+
try {
|
|
3022
|
+
return converter.input({
|
|
3023
|
+
target: "draft-07"
|
|
3024
|
+
});
|
|
3025
|
+
} catch {
|
|
3026
|
+
return void 0;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
__name(toJsonSchema, "toJsonSchema");
|
|
3030
|
+
async function validateProps(schema, value, validator) {
|
|
3031
|
+
if (isStandardSchema(schema)) {
|
|
3032
|
+
const result2 = await schema["~standard"].validate(value);
|
|
3033
|
+
if (result2.issues !== void 0) {
|
|
3034
|
+
return {
|
|
3035
|
+
ok: false,
|
|
3036
|
+
issues: toGenuiIssues(result2.issues)
|
|
3037
|
+
};
|
|
3038
|
+
}
|
|
3039
|
+
return {
|
|
3040
|
+
ok: true,
|
|
3041
|
+
value: result2.value
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
const issues = validator.validate(schema, value);
|
|
3045
|
+
return issues.length > 0 ? {
|
|
3046
|
+
ok: false,
|
|
3047
|
+
issues
|
|
3048
|
+
} : {
|
|
3049
|
+
ok: true,
|
|
3050
|
+
value
|
|
3051
|
+
};
|
|
3052
|
+
}
|
|
3053
|
+
__name(validateProps, "validateProps");
|
|
3054
|
+
function validatePropsSync(schema, value, validator) {
|
|
3055
|
+
if (!isStandardSchema(schema)) {
|
|
3056
|
+
const issues = validator.validate(schema, value);
|
|
3057
|
+
return issues.length > 0 ? {
|
|
3058
|
+
ok: false,
|
|
3059
|
+
issues
|
|
3060
|
+
} : {
|
|
3061
|
+
ok: true,
|
|
3062
|
+
value
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
const result2 = schema["~standard"].validate(value);
|
|
3066
|
+
if (result2 instanceof Promise) {
|
|
3067
|
+
result2.catch(() => void 0);
|
|
3068
|
+
return void 0;
|
|
3069
|
+
}
|
|
3070
|
+
return result2.issues !== void 0 ? {
|
|
3071
|
+
ok: false,
|
|
3072
|
+
issues: toGenuiIssues(result2.issues)
|
|
3073
|
+
} : {
|
|
3074
|
+
ok: true,
|
|
3075
|
+
value: result2.value
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
__name(validatePropsSync, "validatePropsSync");
|
|
3079
|
+
function toGenuiIssues(issues) {
|
|
3080
|
+
return issues.map((issue4) => ({
|
|
3081
|
+
path: (issue4.path ?? []).map((segment) => typeof segment === "object" && segment !== null && "key" in segment ? segment.key : segment),
|
|
3082
|
+
message: issue4.message
|
|
3083
|
+
}));
|
|
3084
|
+
}
|
|
3085
|
+
__name(toGenuiIssues, "toGenuiIssues");
|
|
3086
|
+
function formatIssues(issues) {
|
|
3087
|
+
return issues.map((issue4) => `${issue4.path.length > 0 ? formatPath(issue4.path) : "(root)"}: ${issue4.message}`).join("; ");
|
|
3088
|
+
}
|
|
3089
|
+
__name(formatIssues, "formatIssues");
|
|
3090
|
+
function formatPath(path) {
|
|
3091
|
+
return path.map((segment, index) => typeof segment === "number" ? `[${segment}]` : index === 0 ? segment : `.${segment}`).join("");
|
|
3092
|
+
}
|
|
3093
|
+
__name(formatPath, "formatPath");
|
|
3094
|
+
var builtinJsonSchemaValidator = {
|
|
3095
|
+
validate(schema, value) {
|
|
3096
|
+
const issues = [];
|
|
3097
|
+
check(schema, value, [], schema, issues, 0);
|
|
3098
|
+
return issues;
|
|
3099
|
+
}
|
|
3100
|
+
};
|
|
3101
|
+
var MAX_DEPTH = 64;
|
|
3102
|
+
function typeOf(value) {
|
|
3103
|
+
if (value === null) return "null";
|
|
3104
|
+
if (Array.isArray(value)) return "array";
|
|
3105
|
+
return typeof value;
|
|
3106
|
+
}
|
|
3107
|
+
__name(typeOf, "typeOf");
|
|
3108
|
+
function matchesType(type, value) {
|
|
3109
|
+
switch (type) {
|
|
3110
|
+
case "integer":
|
|
3111
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
3112
|
+
case "number":
|
|
3113
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
3114
|
+
case "object":
|
|
3115
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3116
|
+
default:
|
|
3117
|
+
return typeOf(value) === type;
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
__name(matchesType, "matchesType");
|
|
3121
|
+
function resolveRef(root, ref) {
|
|
3122
|
+
if (ref === "#") return root;
|
|
3123
|
+
if (!ref.startsWith("#/")) return void 0;
|
|
3124
|
+
let current = root;
|
|
3125
|
+
for (const raw of ref.slice(2).split("/")) {
|
|
3126
|
+
const key = raw.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
3127
|
+
if (typeof current !== "object" || current === null) return void 0;
|
|
3128
|
+
current = current[key];
|
|
3129
|
+
}
|
|
3130
|
+
return typeof current === "object" && current !== null ? current : void 0;
|
|
3131
|
+
}
|
|
3132
|
+
__name(resolveRef, "resolveRef");
|
|
3133
|
+
function deepEqual(a, b) {
|
|
3134
|
+
if (a === b) return true;
|
|
3135
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
3136
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
3137
|
+
const keysA = Object.keys(a);
|
|
3138
|
+
const keysB = Object.keys(b);
|
|
3139
|
+
if (keysA.length !== keysB.length) return false;
|
|
3140
|
+
return keysA.every((key) => deepEqual(a[key], b[key]));
|
|
3141
|
+
}
|
|
3142
|
+
__name(deepEqual, "deepEqual");
|
|
3143
|
+
function check(schema, value, path, root, issues, depth) {
|
|
3144
|
+
if (schema === true || schema === void 0) return;
|
|
3145
|
+
if (schema === false) {
|
|
3146
|
+
issues.push({
|
|
3147
|
+
path,
|
|
3148
|
+
message: "is not allowed"
|
|
3149
|
+
});
|
|
3150
|
+
return;
|
|
3151
|
+
}
|
|
3152
|
+
if (typeof schema !== "object" || schema === null) return;
|
|
3153
|
+
if (depth > MAX_DEPTH) {
|
|
3154
|
+
issues.push({
|
|
3155
|
+
path,
|
|
3156
|
+
message: "is nested too deeply"
|
|
3157
|
+
});
|
|
3158
|
+
return;
|
|
3159
|
+
}
|
|
3160
|
+
const s = schema;
|
|
3161
|
+
if (typeof s.$ref === "string") {
|
|
3162
|
+
const target = resolveRef(root, s.$ref);
|
|
3163
|
+
if (target === void 0) {
|
|
3164
|
+
issues.push({
|
|
3165
|
+
path,
|
|
3166
|
+
message: `references unknown schema ${s.$ref}`
|
|
3167
|
+
});
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
check(target, value, path, root, issues, depth + 1);
|
|
3171
|
+
}
|
|
3172
|
+
if (s.type !== void 0) {
|
|
3173
|
+
const types = Array.isArray(s.type) ? s.type : [
|
|
3174
|
+
s.type
|
|
3175
|
+
];
|
|
3176
|
+
if (!types.some((type) => matchesType(type, value))) {
|
|
3177
|
+
issues.push({
|
|
3178
|
+
path,
|
|
3179
|
+
message: `must be ${types.join(" or ")}`
|
|
3180
|
+
});
|
|
3181
|
+
return;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
if (Array.isArray(s.enum) && !s.enum.some((option) => deepEqual(option, value))) {
|
|
3185
|
+
issues.push({
|
|
3186
|
+
path,
|
|
3187
|
+
message: `must be one of ${s.enum.map((option) => JSON.stringify(option)).join(", ")}`
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3190
|
+
if ("const" in s && !deepEqual(s.const, value)) {
|
|
3191
|
+
issues.push({
|
|
3192
|
+
path,
|
|
3193
|
+
message: `must be ${JSON.stringify(s.const)}`
|
|
3194
|
+
});
|
|
3195
|
+
}
|
|
3196
|
+
if (typeof value === "string") {
|
|
3197
|
+
if (typeof s.minLength === "number" && value.length < s.minLength) {
|
|
3198
|
+
issues.push({
|
|
3199
|
+
path,
|
|
3200
|
+
message: `must be at least ${s.minLength} characters`
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
if (typeof s.maxLength === "number" && value.length > s.maxLength) {
|
|
3204
|
+
issues.push({
|
|
3205
|
+
path,
|
|
3206
|
+
message: `must be at most ${s.maxLength} characters`
|
|
3207
|
+
});
|
|
3208
|
+
}
|
|
3209
|
+
if (typeof s.pattern === "string") {
|
|
3210
|
+
let pattern;
|
|
3211
|
+
try {
|
|
3212
|
+
pattern = new RegExp(s.pattern, "u");
|
|
3213
|
+
} catch {
|
|
3214
|
+
pattern = void 0;
|
|
3215
|
+
}
|
|
3216
|
+
if (pattern !== void 0 && !pattern.test(value)) {
|
|
3217
|
+
issues.push({
|
|
3218
|
+
path,
|
|
3219
|
+
message: `must match ${s.pattern}`
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
if (typeof value === "number") {
|
|
3225
|
+
if (typeof s.minimum === "number" && value < s.minimum) {
|
|
3226
|
+
issues.push({
|
|
3227
|
+
path,
|
|
3228
|
+
message: `must be >= ${s.minimum}`
|
|
3229
|
+
});
|
|
3230
|
+
}
|
|
3231
|
+
if (typeof s.maximum === "number" && value > s.maximum) {
|
|
3232
|
+
issues.push({
|
|
3233
|
+
path,
|
|
3234
|
+
message: `must be <= ${s.maximum}`
|
|
3235
|
+
});
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
if (Array.isArray(value)) {
|
|
3239
|
+
if (typeof s.minItems === "number" && value.length < s.minItems) {
|
|
3240
|
+
issues.push({
|
|
3241
|
+
path,
|
|
3242
|
+
message: `must have at least ${s.minItems} items`
|
|
3243
|
+
});
|
|
3244
|
+
}
|
|
3245
|
+
if (typeof s.maxItems === "number" && value.length > s.maxItems) {
|
|
3246
|
+
issues.push({
|
|
3247
|
+
path,
|
|
3248
|
+
message: `must have at most ${s.maxItems} items`
|
|
3249
|
+
});
|
|
3250
|
+
}
|
|
3251
|
+
if (s.items !== void 0 && !Array.isArray(s.items)) {
|
|
3252
|
+
value.forEach((item, index) => {
|
|
3253
|
+
check(s.items, item, [
|
|
3254
|
+
...path,
|
|
3255
|
+
index
|
|
3256
|
+
], root, issues, depth + 1);
|
|
3257
|
+
});
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
if (matchesType("object", value)) {
|
|
3261
|
+
const record2 = value;
|
|
3262
|
+
const properties = typeof s.properties === "object" && s.properties !== null ? s.properties : {};
|
|
3263
|
+
if (Array.isArray(s.required)) {
|
|
3264
|
+
for (const key of s.required) {
|
|
3265
|
+
if (record2[key] === void 0) {
|
|
3266
|
+
issues.push({
|
|
3267
|
+
path: [
|
|
3268
|
+
...path,
|
|
3269
|
+
key
|
|
3270
|
+
],
|
|
3271
|
+
message: "is required"
|
|
3272
|
+
});
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
for (const [key, entry] of Object.entries(record2)) {
|
|
3277
|
+
if (key in properties) {
|
|
3278
|
+
if (entry !== void 0) {
|
|
3279
|
+
check(properties[key], entry, [
|
|
3280
|
+
...path,
|
|
3281
|
+
key
|
|
3282
|
+
], root, issues, depth + 1);
|
|
3283
|
+
}
|
|
3284
|
+
} else if (s.additionalProperties === false) {
|
|
3285
|
+
issues.push({
|
|
3286
|
+
path: [
|
|
3287
|
+
...path,
|
|
3288
|
+
key
|
|
3289
|
+
],
|
|
3290
|
+
message: "is not a known property"
|
|
3291
|
+
});
|
|
3292
|
+
} else if (typeof s.additionalProperties === "object" && s.additionalProperties !== null) {
|
|
3293
|
+
check(s.additionalProperties, entry, [
|
|
3294
|
+
...path,
|
|
3295
|
+
key
|
|
3296
|
+
], root, issues, depth + 1);
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
if (Array.isArray(s.allOf)) {
|
|
3301
|
+
for (const sub of s.allOf) check(sub, value, path, root, issues, depth + 1);
|
|
3302
|
+
}
|
|
3303
|
+
if (Array.isArray(s.anyOf) || Array.isArray(s.oneOf)) {
|
|
3304
|
+
const options = Array.isArray(s.anyOf) ? s.anyOf : s.oneOf;
|
|
3305
|
+
const passing = options.filter((sub) => {
|
|
3306
|
+
const nested = [];
|
|
3307
|
+
check(sub, value, path, root, nested, depth + 1);
|
|
3308
|
+
return nested.length === 0;
|
|
3309
|
+
}).length;
|
|
3310
|
+
if (Array.isArray(s.anyOf) ? passing === 0 : passing !== 1) {
|
|
3311
|
+
issues.push({
|
|
3312
|
+
path,
|
|
3313
|
+
message: Array.isArray(s.anyOf) ? "does not match any allowed shape" : "must match exactly one allowed shape"
|
|
3314
|
+
});
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
if (s.not !== void 0) {
|
|
3318
|
+
const nested = [];
|
|
3319
|
+
check(s.not, value, path, root, nested, depth + 1);
|
|
3320
|
+
if (nested.length === 0) {
|
|
3321
|
+
issues.push({
|
|
3322
|
+
path,
|
|
3323
|
+
message: "matches a shape that is not allowed"
|
|
3324
|
+
});
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
__name(check, "check");
|
|
3329
|
+
|
|
3330
|
+
// src/genui/catalog.ts
|
|
3331
|
+
var COMPONENT_NAME = /^[A-Za-z][A-Za-z0-9]{0,63}$/;
|
|
3332
|
+
function defineComponent(definition) {
|
|
3333
|
+
if (!COMPONENT_NAME.test(definition.name)) {
|
|
3334
|
+
throw new Error(`genui: component name "${definition.name}" must be letters and digits, starting with a letter (e.g. DataTable)`);
|
|
3335
|
+
}
|
|
3336
|
+
if (definition.version !== void 0 && (!Number.isSafeInteger(definition.version) || definition.version <= 0)) throw new RangeError("genui: component version must be a positive safe integer");
|
|
3337
|
+
if (definition.fallbackText !== void 0 && typeof definition.fallbackText !== "function") throw new TypeError("genui: fallbackText must be a function");
|
|
3338
|
+
return definition;
|
|
3339
|
+
}
|
|
3340
|
+
__name(defineComponent, "defineComponent");
|
|
3341
|
+
function defineCatalog(components, options = {}) {
|
|
3342
|
+
const byName = /* @__PURE__ */ new Map();
|
|
3343
|
+
for (const component of components) {
|
|
3344
|
+
defineComponent(component);
|
|
3345
|
+
if (byName.has(component.name)) {
|
|
3346
|
+
throw new Error(`genui: component "${component.name}" is defined twice in one catalog`);
|
|
3347
|
+
}
|
|
3348
|
+
byName.set(component.name, component);
|
|
3349
|
+
}
|
|
3350
|
+
return buildCatalog(byName, options.jsonSchemaValidator ?? builtinJsonSchemaValidator);
|
|
3351
|
+
}
|
|
3352
|
+
__name(defineCatalog, "defineCatalog");
|
|
3353
|
+
function buildCatalog(byName, validator) {
|
|
3354
|
+
const list = Object.freeze([
|
|
3355
|
+
...byName.values()
|
|
3356
|
+
]);
|
|
3357
|
+
return {
|
|
3358
|
+
components: list,
|
|
3359
|
+
validator,
|
|
3360
|
+
get: /* @__PURE__ */ __name((name) => byName.get(name), "get"),
|
|
3361
|
+
has: /* @__PURE__ */ __name((name) => byName.has(name), "has"),
|
|
3362
|
+
modelComponents: /* @__PURE__ */ __name(() => list.filter((component) => component.internal !== true), "modelComponents"),
|
|
3363
|
+
async validate(component, props) {
|
|
3364
|
+
const definition = byName.get(component);
|
|
3365
|
+
if (definition === void 0) {
|
|
3366
|
+
return {
|
|
3367
|
+
ok: false,
|
|
3368
|
+
issues: [
|
|
3369
|
+
{
|
|
3370
|
+
path: [],
|
|
3371
|
+
message: `unknown component "${component}"`
|
|
3372
|
+
}
|
|
3373
|
+
]
|
|
3374
|
+
};
|
|
3375
|
+
}
|
|
3376
|
+
const result2 = await validateProps(definition.props, props, validator);
|
|
3377
|
+
return result2;
|
|
3378
|
+
},
|
|
3379
|
+
validateSync(component, props) {
|
|
3380
|
+
const definition = byName.get(component);
|
|
3381
|
+
if (definition === void 0) {
|
|
3382
|
+
return {
|
|
3383
|
+
ok: false,
|
|
3384
|
+
issues: [
|
|
3385
|
+
{
|
|
3386
|
+
path: [],
|
|
3387
|
+
message: `unknown component "${component}"`
|
|
3388
|
+
}
|
|
3389
|
+
]
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3392
|
+
return validatePropsSync(definition.props, props, validator);
|
|
3393
|
+
},
|
|
3394
|
+
jsonSchemaFor(component) {
|
|
3395
|
+
const definition = byName.get(component);
|
|
3396
|
+
return definition === void 0 ? void 0 : toJsonSchema(definition.props);
|
|
3397
|
+
},
|
|
3398
|
+
extend(more) {
|
|
3399
|
+
const next = new Map(byName);
|
|
3400
|
+
for (const component of more) {
|
|
3401
|
+
defineComponent(component);
|
|
3402
|
+
next.set(component.name, component);
|
|
3403
|
+
}
|
|
3404
|
+
return buildCatalog(next, validator);
|
|
3405
|
+
}
|
|
3406
|
+
};
|
|
3407
|
+
}
|
|
3408
|
+
__name(buildCatalog, "buildCatalog");
|
|
3409
|
+
|
|
3410
|
+
// src/genui/tree.ts
|
|
3411
|
+
var GENUI_TREE_COMPONENT = "genui:tree";
|
|
3412
|
+
async function validateTree(catalog, tree, limits = {}) {
|
|
3413
|
+
const maxDepth = limits.maxDepth ?? 12;
|
|
3414
|
+
const maxNodes = limits.maxNodes ?? 200;
|
|
3415
|
+
const issues = [];
|
|
3416
|
+
let nodes = 0;
|
|
3417
|
+
const visit = /* @__PURE__ */ __name(async (node, path, depth) => {
|
|
3418
|
+
nodes += 1;
|
|
3419
|
+
if (nodes > maxNodes) {
|
|
3420
|
+
if (nodes === maxNodes + 1) {
|
|
3421
|
+
issues.push({
|
|
3422
|
+
path,
|
|
3423
|
+
message: `the tree has more than ${maxNodes} elements`
|
|
3424
|
+
});
|
|
3425
|
+
}
|
|
3426
|
+
return void 0;
|
|
3427
|
+
}
|
|
3428
|
+
if (depth > maxDepth) {
|
|
3429
|
+
issues.push({
|
|
3430
|
+
path,
|
|
3431
|
+
message: `the tree is nested deeper than ${maxDepth} levels`
|
|
3432
|
+
});
|
|
3433
|
+
return void 0;
|
|
3434
|
+
}
|
|
3435
|
+
if (typeof node !== "object" || node === null || Array.isArray(node)) {
|
|
3436
|
+
issues.push({
|
|
3437
|
+
path,
|
|
3438
|
+
message: "must be an element object { type, props, children? }"
|
|
3439
|
+
});
|
|
3440
|
+
return void 0;
|
|
3441
|
+
}
|
|
3442
|
+
const element = node;
|
|
3443
|
+
if (typeof element.type !== "string") {
|
|
3444
|
+
issues.push({
|
|
3445
|
+
path: [
|
|
3446
|
+
...path,
|
|
3447
|
+
"type"
|
|
3448
|
+
],
|
|
3449
|
+
message: "must be a component name"
|
|
3450
|
+
});
|
|
3451
|
+
return void 0;
|
|
3452
|
+
}
|
|
3453
|
+
const definition = catalog.get(element.type);
|
|
3454
|
+
if (definition === void 0 || definition.internal === true) {
|
|
3455
|
+
issues.push({
|
|
3456
|
+
path: [
|
|
3457
|
+
...path,
|
|
3458
|
+
"type"
|
|
3459
|
+
],
|
|
3460
|
+
message: `unknown component "${element.type}" (allowed: ${catalog.modelComponents().map((component) => component.name).join(", ")})`
|
|
3461
|
+
});
|
|
3462
|
+
return void 0;
|
|
3463
|
+
}
|
|
3464
|
+
const validated = await catalog.validate(element.type, element.props ?? {});
|
|
3465
|
+
let props = {};
|
|
3466
|
+
if (!validated.ok) {
|
|
3467
|
+
for (const issue4 of validated.issues) {
|
|
3468
|
+
issues.push({
|
|
3469
|
+
path: [
|
|
3470
|
+
...path,
|
|
3471
|
+
"props",
|
|
3472
|
+
...issue4.path
|
|
3473
|
+
],
|
|
3474
|
+
message: issue4.message
|
|
3475
|
+
});
|
|
3476
|
+
}
|
|
3477
|
+
} else {
|
|
3478
|
+
props = validated.value;
|
|
3479
|
+
}
|
|
3480
|
+
const rawChildren = parseChildrenIfStringified(element.children);
|
|
3481
|
+
if (rawChildren === void 0 || rawChildren === null) {
|
|
3482
|
+
return {
|
|
3483
|
+
type: element.type,
|
|
3484
|
+
props
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3487
|
+
if (!Array.isArray(rawChildren)) {
|
|
3488
|
+
issues.push({
|
|
3489
|
+
path: [
|
|
3490
|
+
...path,
|
|
3491
|
+
"children"
|
|
3492
|
+
],
|
|
3493
|
+
message: "must be an array of elements (a literal array, not a string)"
|
|
3494
|
+
});
|
|
3495
|
+
return void 0;
|
|
3496
|
+
}
|
|
3497
|
+
if (rawChildren.length > 0 && definition.children !== true) {
|
|
3498
|
+
issues.push({
|
|
3499
|
+
path: [
|
|
3500
|
+
...path,
|
|
3501
|
+
"children"
|
|
3502
|
+
],
|
|
3503
|
+
message: `${element.type} does not take children`
|
|
3504
|
+
});
|
|
3505
|
+
return void 0;
|
|
3506
|
+
}
|
|
3507
|
+
const children = [];
|
|
3508
|
+
for (const [index, child] of rawChildren.entries()) {
|
|
3509
|
+
const next = await visit(child, [
|
|
3510
|
+
...path,
|
|
3511
|
+
"children",
|
|
3512
|
+
index
|
|
3513
|
+
], depth + 1);
|
|
3514
|
+
if (next !== void 0) {
|
|
3515
|
+
children.push(next);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
return children.length > 0 ? {
|
|
3519
|
+
type: element.type,
|
|
3520
|
+
props,
|
|
3521
|
+
children
|
|
3522
|
+
} : {
|
|
3523
|
+
type: element.type,
|
|
3524
|
+
props
|
|
3525
|
+
};
|
|
3526
|
+
}, "visit");
|
|
3527
|
+
const root = await visit(tree, [], 1);
|
|
3528
|
+
return issues.length > 0 || root === void 0 ? {
|
|
3529
|
+
ok: false,
|
|
3530
|
+
issues: issues.length > 0 ? issues : [
|
|
3531
|
+
{
|
|
3532
|
+
path: [],
|
|
3533
|
+
message: "is invalid"
|
|
3534
|
+
}
|
|
3535
|
+
]
|
|
3536
|
+
} : {
|
|
3537
|
+
ok: true,
|
|
3538
|
+
value: root
|
|
3539
|
+
};
|
|
3540
|
+
}
|
|
3541
|
+
__name(validateTree, "validateTree");
|
|
3542
|
+
function parseChildrenIfStringified(value) {
|
|
3543
|
+
if (typeof value !== "string") return value;
|
|
3544
|
+
const trimmed = value.trim();
|
|
3545
|
+
if (!trimmed.startsWith("[")) return value;
|
|
3546
|
+
return leadingJsonArray(trimmed) ?? value;
|
|
3547
|
+
}
|
|
3548
|
+
__name(parseChildrenIfStringified, "parseChildrenIfStringified");
|
|
3549
|
+
function leadingJsonArray(text) {
|
|
3550
|
+
let depth = 0;
|
|
3551
|
+
let inString = false;
|
|
3552
|
+
let escaped = false;
|
|
3553
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
3554
|
+
const char = text[index];
|
|
3555
|
+
if (inString) {
|
|
3556
|
+
if (escaped) escaped = false;
|
|
3557
|
+
else if (char === "\\") escaped = true;
|
|
3558
|
+
else if (char === '"') inString = false;
|
|
3559
|
+
continue;
|
|
3560
|
+
}
|
|
3561
|
+
if (char === '"') inString = true;
|
|
3562
|
+
else if (char === "[" || char === "{") depth += 1;
|
|
3563
|
+
else if (char === "]" || char === "}") {
|
|
3564
|
+
depth -= 1;
|
|
3565
|
+
if (depth === 0) {
|
|
3566
|
+
try {
|
|
3567
|
+
const parsed = JSON.parse(text.slice(0, index + 1));
|
|
3568
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
3569
|
+
} catch {
|
|
3570
|
+
return void 0;
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
return void 0;
|
|
3576
|
+
}
|
|
3577
|
+
__name(leadingJsonArray, "leadingJsonArray");
|
|
3578
|
+
|
|
3579
|
+
// src/genui/text.ts
|
|
3580
|
+
function componentToText(catalog, component, props) {
|
|
3581
|
+
if (component === GENUI_TREE_COMPONENT) {
|
|
3582
|
+
const root = props.root;
|
|
3583
|
+
return root === void 0 ? "" : treeToText(catalog, root);
|
|
3584
|
+
}
|
|
3585
|
+
const fallback = catalog.get(component)?.fallbackText;
|
|
3586
|
+
if (fallback !== void 0) {
|
|
3587
|
+
try {
|
|
3588
|
+
const text = fallback(props);
|
|
3589
|
+
if (typeof text === "string" && text.trim().length > 0) return text;
|
|
3590
|
+
} catch {
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
return jsonBlock(props);
|
|
3594
|
+
}
|
|
3595
|
+
__name(componentToText, "componentToText");
|
|
3596
|
+
function treeToText(catalog, root) {
|
|
3597
|
+
const out = [];
|
|
3598
|
+
const visit = /* @__PURE__ */ __name((node, depth) => {
|
|
3599
|
+
if (depth > 32) return;
|
|
3600
|
+
const definition = catalog.get(node.type);
|
|
3601
|
+
if (definition?.fallbackText !== void 0) {
|
|
3602
|
+
try {
|
|
3603
|
+
const text = definition.fallbackText(node.props);
|
|
3604
|
+
out.push(typeof text === "string" && text.trim().length > 0 ? text : jsonBlock(node.props));
|
|
3605
|
+
} catch {
|
|
3606
|
+
out.push(jsonBlock(node.props));
|
|
3607
|
+
}
|
|
3608
|
+
} else if (definition?.children !== true) {
|
|
3609
|
+
out.push(jsonBlock(node.props));
|
|
3610
|
+
}
|
|
3611
|
+
for (const child of node.children ?? []) visit(child, depth + 1);
|
|
3612
|
+
}, "visit");
|
|
3613
|
+
visit(root, 0);
|
|
3614
|
+
return out.filter((line) => line.trim().length > 0).join("\n");
|
|
3615
|
+
}
|
|
3616
|
+
__name(treeToText, "treeToText");
|
|
3617
|
+
function jsonBlock(props) {
|
|
3618
|
+
const title = typeof props.title === "string" && props.title.length > 0 ? `*${props.title}*
|
|
3619
|
+
` : "";
|
|
3620
|
+
return `${title}\`\`\`
|
|
3621
|
+
${JSON.stringify(props, null, 2)}
|
|
3622
|
+
\`\`\``;
|
|
3623
|
+
}
|
|
3624
|
+
__name(jsonBlock, "jsonBlock");
|
|
3625
|
+
|
|
3626
|
+
// src/genui/capabilities.ts
|
|
3627
|
+
function validateUiCapabilities(value) {
|
|
3628
|
+
if (!record(value) || Object.keys(value).some((key) => key !== "components") || !Array.isArray(value.components)) throw new TypeError("Invalid UI capabilities");
|
|
3629
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3630
|
+
const components = value.components.map((component) => {
|
|
3631
|
+
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");
|
|
3632
|
+
seen.add(component.name);
|
|
3633
|
+
return {
|
|
3634
|
+
name: component.name,
|
|
3635
|
+
version: Number(component.version)
|
|
3636
|
+
};
|
|
3637
|
+
});
|
|
3638
|
+
return {
|
|
3639
|
+
components
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
__name(validateUiCapabilities, "validateUiCapabilities");
|
|
3643
|
+
function record(value) {
|
|
3644
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3645
|
+
}
|
|
3646
|
+
__name(record, "record");
|
|
3647
|
+
function negotiateCatalog(catalog, capabilities) {
|
|
3648
|
+
if (capabilities === void 0) return catalog;
|
|
3649
|
+
const supported = validateUiCapabilities(capabilities).components;
|
|
3650
|
+
return defineCatalog(catalog.components.filter((component) => supported.some((entry) => entry.name === component.name && entry.version === (component.version ?? 1))), {
|
|
3651
|
+
jsonSchemaValidator: catalog.validator
|
|
3652
|
+
});
|
|
3653
|
+
}
|
|
3654
|
+
__name(negotiateCatalog, "negotiateCatalog");
|
|
3655
|
+
async function prepareUiEmission(catalog, capabilities, component, props, version) {
|
|
3656
|
+
const drawable = negotiateCatalog(catalog, capabilities);
|
|
3657
|
+
if (component === GENUI_TREE_COMPONENT) {
|
|
3658
|
+
if (version !== void 0 && version !== 1) throw new Error("Invalid UI tree version");
|
|
3659
|
+
const validated2 = await validateTree(catalog, props.root);
|
|
3660
|
+
if (!validated2.ok) throw new Error(`Invalid UI tree: ${formatIssues(validated2.issues)}`);
|
|
3661
|
+
const supported = /* @__PURE__ */ __name((node) => drawable.has(node.type) && (node.children ?? []).every(supported), "supported");
|
|
3662
|
+
const versions = /* @__PURE__ */ new Map();
|
|
3663
|
+
const collectVersions = /* @__PURE__ */ __name((node) => {
|
|
3664
|
+
versions.set(node.type, catalog.get(node.type)?.version ?? 1);
|
|
3665
|
+
for (const child of node.children ?? []) collectVersions(child);
|
|
3666
|
+
}, "collectVersions");
|
|
3667
|
+
collectVersions(validated2.value);
|
|
3668
|
+
return supported(validated2.value) ? {
|
|
3669
|
+
kind: "ui",
|
|
3670
|
+
component,
|
|
3671
|
+
props: {
|
|
3672
|
+
root: validated2.value
|
|
3673
|
+
},
|
|
3674
|
+
version: 1,
|
|
3675
|
+
fallbackText: treeToText(catalog, validated2.value),
|
|
3676
|
+
componentVersions: Object.fromEntries(versions)
|
|
3677
|
+
} : {
|
|
3678
|
+
kind: "text",
|
|
3679
|
+
text: treeToText(catalog, validated2.value)
|
|
3680
|
+
};
|
|
3681
|
+
}
|
|
3682
|
+
const definition = catalog.get(component);
|
|
3683
|
+
if (definition === void 0) throw new Error(`Unknown UI component "${component}"`);
|
|
3684
|
+
const currentVersion = definition.version ?? 1;
|
|
3685
|
+
if (version !== void 0 && version !== currentVersion) throw new Error(`Invalid UI component version for "${component}"`);
|
|
3686
|
+
const validated = await catalog.validate(component, props);
|
|
3687
|
+
if (!validated.ok) throw new Error(`Invalid UI props: ${formatIssues(validated.issues)}`);
|
|
3688
|
+
return drawable.has(component) ? {
|
|
3689
|
+
kind: "ui",
|
|
3690
|
+
component,
|
|
3691
|
+
props: validated.value,
|
|
3692
|
+
version: currentVersion,
|
|
3693
|
+
fallbackText: componentToText(catalog, component, validated.value)
|
|
3694
|
+
} : {
|
|
3695
|
+
kind: "text",
|
|
3696
|
+
text: componentToText(catalog, component, validated.value)
|
|
3697
|
+
};
|
|
3698
|
+
}
|
|
3699
|
+
__name(prepareUiEmission, "prepareUiEmission");
|
|
3700
|
+
|
|
3701
|
+
// src/action-proposal-transitions.ts
|
|
3702
|
+
function checkTime(value) {
|
|
3703
|
+
if (!Number.isSafeInteger(value)) throw new RangeError("Action proposal timestamps must be safe integer milliseconds");
|
|
3704
|
+
}
|
|
3705
|
+
__name(checkTime, "checkTime");
|
|
3706
|
+
function checkString(value) {
|
|
3707
|
+
if (typeof value !== "string" || value.length === 0) throw new TypeError("Action proposal identifiers must be nonempty strings");
|
|
3708
|
+
}
|
|
3709
|
+
__name(checkString, "checkString");
|
|
3710
|
+
function validateActionProposalCreation(input) {
|
|
3711
|
+
const allowed = [
|
|
3712
|
+
"id",
|
|
3713
|
+
"tenantRef",
|
|
3714
|
+
"actorRef",
|
|
3715
|
+
"threadId",
|
|
3716
|
+
"originRunId",
|
|
3717
|
+
"originMessageId",
|
|
3718
|
+
"originToolCallId",
|
|
3719
|
+
"toolName",
|
|
3720
|
+
"input",
|
|
3721
|
+
"preparationInput",
|
|
3722
|
+
"executionContext",
|
|
3723
|
+
"confirmation",
|
|
3724
|
+
"approver",
|
|
3725
|
+
"expiresAt",
|
|
3726
|
+
"idempotencyKey",
|
|
3727
|
+
"replacementKey"
|
|
3728
|
+
];
|
|
3729
|
+
if (Object.keys(input).some((key) => !allowed.includes(key))) throw new TypeError("Unknown action proposal creation field");
|
|
3730
|
+
for (const key of [
|
|
3731
|
+
"id",
|
|
3732
|
+
"actorRef",
|
|
3733
|
+
"threadId",
|
|
3734
|
+
"originRunId",
|
|
3735
|
+
"originMessageId",
|
|
3736
|
+
"originToolCallId",
|
|
3737
|
+
"toolName",
|
|
3738
|
+
"approver",
|
|
3739
|
+
"idempotencyKey"
|
|
3740
|
+
]) checkString(input[key]);
|
|
3741
|
+
if (input.tenantRef !== null && typeof input.tenantRef !== "string") throw new TypeError("tenantRef must be an explicit string or null");
|
|
3742
|
+
for (const value of [
|
|
3743
|
+
input.id,
|
|
3744
|
+
input.actorRef,
|
|
3745
|
+
input.threadId,
|
|
3746
|
+
input.tenantRef
|
|
3747
|
+
]) {
|
|
3748
|
+
if (value !== null && value.length > 255) throw new RangeError("Action proposal id and scope must fit 255 UTF-16 code units");
|
|
3749
|
+
}
|
|
3750
|
+
if (input.replacementKey !== void 0) {
|
|
3751
|
+
checkString(input.replacementKey);
|
|
3752
|
+
if (input.replacementKey.length > 255) throw new RangeError("replacementKey must fit 255 UTF-16 code units");
|
|
3753
|
+
}
|
|
3754
|
+
if (Object.hasOwn(input, "executionContext")) {
|
|
3755
|
+
const context = input.executionContext;
|
|
3756
|
+
if (context === null || typeof context !== "object" || Array.isArray(context)) throw new TypeError("executionContext must be a JSON object");
|
|
3757
|
+
const allowedContext = [
|
|
3758
|
+
"agentName",
|
|
3759
|
+
"persona",
|
|
3760
|
+
"requestId",
|
|
3761
|
+
"pageContext",
|
|
3762
|
+
"uiCapabilities"
|
|
3763
|
+
];
|
|
3764
|
+
if (Object.keys(context).some((key) => !allowedContext.includes(key))) throw new TypeError("Unknown execution context field");
|
|
3765
|
+
checkString(context.requestId);
|
|
3766
|
+
if (Object.hasOwn(context, "uiCapabilities")) validateUiCapabilities(context.uiCapabilities);
|
|
3767
|
+
if (Object.hasOwn(context, "agentName")) checkString(context.agentName);
|
|
3768
|
+
if (Object.hasOwn(context, "persona")) checkString(context.persona);
|
|
3769
|
+
if (Object.hasOwn(context, "pageContext")) {
|
|
3770
|
+
const page = context.pageContext;
|
|
3771
|
+
if (page === null || typeof page !== "object" || Array.isArray(page)) throw new TypeError("pageContext must be a JSON object");
|
|
3772
|
+
if (Object.hasOwn(page, "kind") && typeof page.kind !== "string") throw new TypeError("pageContext.kind must be a string");
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
if (input.expiresAt !== null) checkTime(input.expiresAt);
|
|
3776
|
+
checkString(input.confirmation?.title);
|
|
3777
|
+
checkString(input.confirmation?.verb);
|
|
3778
|
+
canonicalActionProposalJson(input);
|
|
3779
|
+
}
|
|
3780
|
+
__name(validateActionProposalCreation, "validateActionProposalCreation");
|
|
3781
|
+
function validateActionProposalListQuery(query = {}) {
|
|
3782
|
+
const limit = query.limit === void 0 ? 100 : query.limit;
|
|
3783
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 1e3) throw new RangeError("limit must be an integer from 1 to 1000");
|
|
3784
|
+
if (query.decision !== void 0 && ![
|
|
3785
|
+
"pending",
|
|
3786
|
+
"approved",
|
|
3787
|
+
"rejected",
|
|
3788
|
+
"expired",
|
|
3789
|
+
"superseded"
|
|
3790
|
+
].includes(query.decision)) throw new TypeError("Unsupported action proposal list decision");
|
|
3791
|
+
if (query.after !== void 0) {
|
|
3792
|
+
const after = query.after;
|
|
3793
|
+
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");
|
|
3794
|
+
checkTime(after.createdAt);
|
|
3795
|
+
checkString(after.id);
|
|
3796
|
+
if (after.id.length > 255) throw new TypeError("Action proposal cursor id is too long");
|
|
3797
|
+
}
|
|
3798
|
+
return limit;
|
|
3799
|
+
}
|
|
3800
|
+
__name(validateActionProposalListQuery, "validateActionProposalListQuery");
|
|
3801
|
+
function canonicalActionProposalJson(value) {
|
|
3802
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
3803
|
+
const sort = /* @__PURE__ */ __name((item) => {
|
|
3804
|
+
if (item === null || typeof item === "string" || typeof item === "boolean") return item;
|
|
3805
|
+
if (typeof item === "number" && Number.isFinite(item)) return item;
|
|
3806
|
+
if (typeof item !== "object" || item === null || ancestors.has(item)) throw new TypeError("Action proposals require finite, acyclic JSON values");
|
|
3807
|
+
const prototype = Object.getPrototypeOf(item);
|
|
3808
|
+
if (!Array.isArray(item) && prototype !== Object.prototype && prototype !== null) throw new TypeError("Action proposals require plain JSON objects");
|
|
3809
|
+
ancestors.add(item);
|
|
3810
|
+
const sorted = Array.isArray(item) ? Array.from(item, sort) : Object.fromEntries(Object.keys(item).sort().map((key) => [
|
|
3811
|
+
key,
|
|
3812
|
+
sort(item[key])
|
|
3813
|
+
]));
|
|
3814
|
+
ancestors.delete(item);
|
|
3815
|
+
return sorted;
|
|
3816
|
+
}, "sort");
|
|
3817
|
+
return JSON.stringify(sort(value));
|
|
3818
|
+
}
|
|
3819
|
+
__name(canonicalActionProposalJson, "canonicalActionProposalJson");
|
|
3820
|
+
function snapshotActionProposal(value) {
|
|
3821
|
+
return JSON.parse(canonicalActionProposalJson(value));
|
|
3822
|
+
}
|
|
3823
|
+
__name(snapshotActionProposal, "snapshotActionProposal");
|
|
3824
|
+
function actionProposalScopeMatches(row, scope) {
|
|
3825
|
+
return row.tenantRef === scope.tenantRef && row.actorRef === scope.actorRef && row.threadId === scope.threadId;
|
|
3826
|
+
}
|
|
3827
|
+
__name(actionProposalScopeMatches, "actionProposalScopeMatches");
|
|
3828
|
+
function initialActionProposal(input, now) {
|
|
3829
|
+
validateActionProposalCreation(input);
|
|
3830
|
+
checkTime(now);
|
|
3831
|
+
return snapshotActionProposal({
|
|
3832
|
+
...input,
|
|
3833
|
+
decision: "pending",
|
|
3834
|
+
decisionAudit: null,
|
|
3835
|
+
execution: null,
|
|
3836
|
+
createdAt: now,
|
|
3837
|
+
updatedAt: now
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3840
|
+
__name(initialActionProposal, "initialActionProposal");
|
|
3841
|
+
function actionProposalCreationMatches(row, input) {
|
|
3842
|
+
validateActionProposalCreation(input);
|
|
3843
|
+
const { decision: _decision, decisionAudit: _audit, execution: _execution, createdAt: _created, updatedAt: _updated, supersededBy: _supersededBy, outcome: _outcome, outcomeDelivery: _delivery, ...original } = row;
|
|
3844
|
+
return canonicalActionProposalJson(original) === canonicalActionProposalJson(input);
|
|
3845
|
+
}
|
|
3846
|
+
__name(actionProposalCreationMatches, "actionProposalCreationMatches");
|
|
3847
|
+
function result(status, proposal) {
|
|
3848
|
+
return {
|
|
3849
|
+
status,
|
|
3850
|
+
proposal: snapshotActionProposal(proposal)
|
|
3851
|
+
};
|
|
3852
|
+
}
|
|
3853
|
+
__name(result, "result");
|
|
3854
|
+
function transitionActionProposalDecision(row, command, now) {
|
|
3855
|
+
checkTime(now);
|
|
3856
|
+
if (![
|
|
3857
|
+
"approved",
|
|
3858
|
+
"rejected",
|
|
3859
|
+
"expired"
|
|
3860
|
+
].includes(command.decision)) throw new TypeError("Unsupported action proposal decision");
|
|
3861
|
+
checkString(command.actorRef);
|
|
3862
|
+
checkString(command.via);
|
|
3863
|
+
if (command.reason !== void 0 && typeof command.reason !== "string") throw new TypeError("reason must be a string");
|
|
3864
|
+
if (command.remember !== void 0 && typeof command.remember !== "boolean") throw new TypeError("remember must be a boolean");
|
|
3865
|
+
if (row.decision !== "pending") {
|
|
3866
|
+
return result(row.decision === command.decision ? "unchanged" : row.decision === "expired" ? "expired" : "conflict", row);
|
|
3867
|
+
}
|
|
3868
|
+
const next = snapshotActionProposal(row);
|
|
3869
|
+
if (row.expiresAt !== null && now >= row.expiresAt) {
|
|
3870
|
+
next.decision = "expired";
|
|
3871
|
+
next.decisionAudit = {
|
|
3872
|
+
actorRef: "system",
|
|
3873
|
+
via: "expiry",
|
|
3874
|
+
at: now
|
|
3875
|
+
};
|
|
3876
|
+
next.updatedAt = now;
|
|
3877
|
+
return result(command.decision === "expired" ? "applied" : "expired", attachActionProposalOutcome(next, now));
|
|
3878
|
+
}
|
|
3879
|
+
if (command.decision === "expired") return result("conflict", row);
|
|
3880
|
+
const { decision, ...audit } = command;
|
|
3881
|
+
next.decision = decision;
|
|
3882
|
+
next.decisionAudit = {
|
|
3883
|
+
actorRef: audit.actorRef,
|
|
3884
|
+
via: audit.via,
|
|
3885
|
+
at: now,
|
|
3886
|
+
...audit.reason === void 0 ? {} : {
|
|
3887
|
+
reason: audit.reason
|
|
3888
|
+
},
|
|
3889
|
+
...audit.remember === void 0 ? {} : {
|
|
3890
|
+
remember: audit.remember
|
|
3891
|
+
}
|
|
3892
|
+
};
|
|
3893
|
+
next.updatedAt = now;
|
|
3894
|
+
if (decision === "approved") next.execution = {
|
|
3895
|
+
status: "queued",
|
|
3896
|
+
generation: 0,
|
|
3897
|
+
lease: null
|
|
3898
|
+
};
|
|
3899
|
+
return result("applied", decision === "approved" ? next : attachActionProposalOutcome(next, now));
|
|
3900
|
+
}
|
|
3901
|
+
__name(transitionActionProposalDecision, "transitionActionProposalDecision");
|
|
3902
|
+
function checkLeaseMs(leaseMs, now) {
|
|
3903
|
+
checkTime(now);
|
|
3904
|
+
if (!Number.isSafeInteger(leaseMs) || leaseMs <= 0 || !Number.isSafeInteger(now + leaseMs)) throw new RangeError("leaseMs must be finite and positive");
|
|
3905
|
+
}
|
|
3906
|
+
__name(checkLeaseMs, "checkLeaseMs");
|
|
3907
|
+
function transitionActionProposalClaim(row, command, now, token) {
|
|
3908
|
+
checkLeaseMs(command.leaseMs, now);
|
|
3909
|
+
checkString(command.workerId);
|
|
3910
|
+
checkString(token);
|
|
3911
|
+
const execution = row.execution;
|
|
3912
|
+
if (row.decision !== "approved" || !execution || execution.status !== "queued" && !(execution.status === "executing" && execution.lease && now >= execution.lease.expiresAt)) return result("conflict", row);
|
|
3913
|
+
const next = snapshotActionProposal(row);
|
|
3914
|
+
const generation = execution.generation + 1;
|
|
3915
|
+
next.execution = {
|
|
3916
|
+
status: "executing",
|
|
3917
|
+
generation,
|
|
3918
|
+
lease: {
|
|
3919
|
+
token,
|
|
3920
|
+
generation,
|
|
3921
|
+
workerId: command.workerId,
|
|
3922
|
+
expiresAt: now + command.leaseMs
|
|
3923
|
+
}
|
|
3924
|
+
};
|
|
3925
|
+
next.updatedAt = now;
|
|
3926
|
+
return result("applied", next);
|
|
3927
|
+
}
|
|
3928
|
+
__name(transitionActionProposalClaim, "transitionActionProposalClaim");
|
|
3929
|
+
function leaseStatus(row, command, now) {
|
|
3930
|
+
checkTime(now);
|
|
3931
|
+
checkString(command.token);
|
|
3932
|
+
if (!Number.isSafeInteger(command.generation) || command.generation < 1) throw new RangeError("Invalid lease generation");
|
|
3933
|
+
const work = row.execution;
|
|
3934
|
+
if (row.decision !== "approved" || work?.status !== "executing" || !work.lease || work.generation !== command.generation || work.lease.generation !== command.generation || work.lease.token !== command.token) return "conflict";
|
|
3935
|
+
return now >= work.lease.expiresAt ? "expired" : "valid";
|
|
3936
|
+
}
|
|
3937
|
+
__name(leaseStatus, "leaseStatus");
|
|
3938
|
+
function transitionActionProposalLease(row, command, now) {
|
|
3939
|
+
checkLeaseMs(command.leaseMs, now);
|
|
3940
|
+
const status = leaseStatus(row, command, now);
|
|
3941
|
+
if (status !== "valid") return result(status, row);
|
|
3942
|
+
const next = snapshotActionProposal(row);
|
|
3943
|
+
if (next.execution?.lease) next.execution.lease.expiresAt = Math.max(next.execution.lease.expiresAt, now + command.leaseMs);
|
|
3944
|
+
next.updatedAt = now;
|
|
3945
|
+
return result("applied", next);
|
|
3946
|
+
}
|
|
3947
|
+
__name(transitionActionProposalLease, "transitionActionProposalLease");
|
|
3948
|
+
function transitionActionProposalSettlement(row, command, now) {
|
|
3949
|
+
checkTime(now);
|
|
3950
|
+
if (command.status !== "succeeded" && command.status !== "failed") throw new TypeError("Unsupported settlement status");
|
|
3951
|
+
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");
|
|
3952
|
+
const status = leaseStatus(row, command, now);
|
|
3953
|
+
if (status !== "valid") return result(status, row);
|
|
3954
|
+
const next = snapshotActionProposal(row);
|
|
3955
|
+
next.execution = command.status === "succeeded" ? {
|
|
3956
|
+
status: "succeeded",
|
|
3957
|
+
generation: command.generation,
|
|
3958
|
+
lease: null,
|
|
3959
|
+
...command.result === void 0 ? {} : {
|
|
3960
|
+
result: command.result
|
|
3961
|
+
}
|
|
3962
|
+
} : {
|
|
3963
|
+
status: "failed",
|
|
3964
|
+
generation: command.generation,
|
|
3965
|
+
lease: null,
|
|
3966
|
+
error: command.error
|
|
3967
|
+
};
|
|
3968
|
+
if (command.ui !== void 0) canonicalActionProposalJson(command.ui);
|
|
3969
|
+
if (command.text !== void 0 && typeof command.text !== "string") throw new TypeError("Outcome text must be a string");
|
|
3970
|
+
next.updatedAt = now;
|
|
3971
|
+
return result("applied", attachActionProposalOutcome(next, now, command.ui, command.text));
|
|
3972
|
+
}
|
|
3973
|
+
__name(transitionActionProposalSettlement, "transitionActionProposalSettlement");
|
|
3974
|
+
function transitionActionProposalSupersession(row, replacement, command, now) {
|
|
3975
|
+
checkTime(now);
|
|
3976
|
+
checkString(command.replacementProposalId);
|
|
3977
|
+
checkString(command.actorRef);
|
|
3978
|
+
checkString(command.via);
|
|
3979
|
+
if (replacement.id !== command.replacementProposalId || row.id === replacement.id || !actionProposalScopeMatches(row, replacement) || row.toolName !== replacement.toolName || !row.replacementKey || row.replacementKey !== replacement.replacementKey) return result("conflict", row);
|
|
3980
|
+
if (row.decision === "superseded") return result(row.supersededBy === replacement.id ? "unchanged" : "conflict", row);
|
|
3981
|
+
if (row.decision !== "pending") return result("conflict", row);
|
|
3982
|
+
if (row.expiresAt !== null && now >= row.expiresAt) return {
|
|
3983
|
+
...transitionActionProposalDecision(row, {
|
|
3984
|
+
decision: "expired",
|
|
3985
|
+
actorRef: "system",
|
|
3986
|
+
via: "expiry"
|
|
3987
|
+
}, now),
|
|
3988
|
+
status: "expired"
|
|
3989
|
+
};
|
|
3990
|
+
const next = snapshotActionProposal({
|
|
3991
|
+
...row,
|
|
3992
|
+
decision: "superseded",
|
|
3993
|
+
supersededBy: replacement.id,
|
|
3994
|
+
decisionAudit: {
|
|
3995
|
+
actorRef: command.actorRef,
|
|
3996
|
+
via: command.via,
|
|
3997
|
+
replacementProposalId: replacement.id,
|
|
3998
|
+
at: now
|
|
3999
|
+
},
|
|
4000
|
+
updatedAt: now
|
|
4001
|
+
});
|
|
4002
|
+
return result("applied", attachActionProposalOutcome(next, now));
|
|
4003
|
+
}
|
|
4004
|
+
__name(transitionActionProposalSupersession, "transitionActionProposalSupersession");
|
|
4005
|
+
|
|
2774
4006
|
// src/tool-registry.ts
|
|
2775
4007
|
var ToolForbiddenError = class extends Error {
|
|
2776
4008
|
static {
|
|
@@ -2813,6 +4045,35 @@ var ToolInputInvalidError = class extends Error {
|
|
|
2813
4045
|
this.name = "ToolInputInvalidError";
|
|
2814
4046
|
}
|
|
2815
4047
|
};
|
|
4048
|
+
var ToolPreflightDeniedError = class extends Error {
|
|
4049
|
+
static {
|
|
4050
|
+
__name(this, "ToolPreflightDeniedError");
|
|
4051
|
+
}
|
|
4052
|
+
toolName;
|
|
4053
|
+
reason;
|
|
4054
|
+
constructor(toolName, reason) {
|
|
4055
|
+
super(reason), this.toolName = toolName, this.reason = reason;
|
|
4056
|
+
this.name = "ToolPreflightDeniedError";
|
|
4057
|
+
}
|
|
4058
|
+
};
|
|
4059
|
+
var ToolInputDriftError = class extends Error {
|
|
4060
|
+
static {
|
|
4061
|
+
__name(this, "ToolInputDriftError");
|
|
4062
|
+
}
|
|
4063
|
+
toolName;
|
|
4064
|
+
constructor(toolName) {
|
|
4065
|
+
super(`Tool "${toolName}" input differs from its trusted snapshot`), this.toolName = toolName;
|
|
4066
|
+
this.name = "ToolInputDriftError";
|
|
4067
|
+
}
|
|
4068
|
+
};
|
|
4069
|
+
function assertTrustedInput(name, value, approved) {
|
|
4070
|
+
try {
|
|
4071
|
+
if (canonicalActionProposalJson(value) === canonicalActionProposalJson(approved)) return;
|
|
4072
|
+
} catch {
|
|
4073
|
+
}
|
|
4074
|
+
throw new ToolInputDriftError(name);
|
|
4075
|
+
}
|
|
4076
|
+
__name(assertTrustedInput, "assertTrustedInput");
|
|
2816
4077
|
var ToolRegistry = class {
|
|
2817
4078
|
static {
|
|
2818
4079
|
__name(this, "ToolRegistry");
|
|
@@ -2860,11 +4121,12 @@ var ToolRegistry = class {
|
|
|
2860
4121
|
*/
|
|
2861
4122
|
async definitionsFor(actor, policy, allowedTools, scope = {}) {
|
|
2862
4123
|
const visible = await this.visibleEntries(actor, policy, allowedTools);
|
|
2863
|
-
|
|
4124
|
+
const definitions = await Promise.all(visible.map(async ({ spec, handler }) => {
|
|
2864
4125
|
const override = handler.describe === void 0 ? void 0 : await handler.describe({
|
|
2865
4126
|
actor,
|
|
2866
4127
|
...scope
|
|
2867
4128
|
});
|
|
4129
|
+
if (override?.available === false) return null;
|
|
2868
4130
|
return {
|
|
2869
4131
|
name: spec.name,
|
|
2870
4132
|
kind: spec.kind,
|
|
@@ -2872,6 +4134,7 @@ var ToolRegistry = class {
|
|
|
2872
4134
|
inputSchema: override?.inputSchema ?? spec.inputSchema
|
|
2873
4135
|
};
|
|
2874
4136
|
}));
|
|
4137
|
+
return definitions.filter((definition) => definition !== null);
|
|
2875
4138
|
}
|
|
2876
4139
|
/**
|
|
2877
4140
|
* The specs {@link definitionsFor} offers the model, whole — the same four gates (allow-list,
|
|
@@ -2896,7 +4159,41 @@ var ToolRegistry = class {
|
|
|
2896
4159
|
* a call can reach here from a replayed durable step or an approval granted before the flag
|
|
2897
4160
|
* moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.
|
|
2898
4161
|
*/
|
|
2899
|
-
async invoke(name, input, ctx, policy) {
|
|
4162
|
+
async invoke(name, input, ctx, policy, options = {}) {
|
|
4163
|
+
const { entry, value, ctx: withEmit } = await this.validated(name, input, ctx, policy, options);
|
|
4164
|
+
const trusted = Object.hasOwn(options, "approvedInput");
|
|
4165
|
+
if (trusted) assertTrustedInput(name, value, options.approvedInput);
|
|
4166
|
+
const executionInput = trusted ? snapshotActionProposal(value) : value;
|
|
4167
|
+
const hookInput = trusted ? snapshotActionProposal(executionInput) : value;
|
|
4168
|
+
const result2 = entry.spec.kind === "action" ? await entry.handler.preflight?.(hookInput, withEmit, {
|
|
4169
|
+
phase: "execute"
|
|
4170
|
+
}) : void 0;
|
|
4171
|
+
if (trusted) assertTrustedInput(name, hookInput, executionInput);
|
|
4172
|
+
if (result2?.status === "denied") throw new ToolPreflightDeniedError(name, result2.reason);
|
|
4173
|
+
if (result2?.status === "completed") return result2.output;
|
|
4174
|
+
return entry.handler.execute(executionInput, withEmit);
|
|
4175
|
+
}
|
|
4176
|
+
/** Authorize and validate without executing. The caller journals this result before approval. */
|
|
4177
|
+
async prepare(name, input, ctx, policy, options = {}) {
|
|
4178
|
+
return (await this.prepareValidated(name, input, ctx, policy, options)).preflight;
|
|
4179
|
+
}
|
|
4180
|
+
/** Expose the single schema parse; snapshotInput opts proposal callers into immutable JSON. */
|
|
4181
|
+
async prepareValidated(name, input, ctx, policy, options = {}) {
|
|
4182
|
+
const { entry, value, ctx: withEmit } = await this.validated(name, input, ctx, policy, options);
|
|
4183
|
+
const normalized = options.snapshotInput === true ? snapshotActionProposal(value) : value;
|
|
4184
|
+
const hookInput = options.snapshotInput === true ? snapshotActionProposal(normalized) : value;
|
|
4185
|
+
const preflight = (entry.spec.kind === "action" ? await entry.handler.preflight?.(hookInput, withEmit, {
|
|
4186
|
+
phase: "prepare"
|
|
4187
|
+
}) : void 0) ?? {
|
|
4188
|
+
status: "ready"
|
|
4189
|
+
};
|
|
4190
|
+
if (options.snapshotInput === true) assertTrustedInput(name, hookInput, normalized);
|
|
4191
|
+
return {
|
|
4192
|
+
input: normalized,
|
|
4193
|
+
preflight
|
|
4194
|
+
};
|
|
4195
|
+
}
|
|
4196
|
+
async validated(name, input, ctx, policy, options) {
|
|
2900
4197
|
const entry = this.entries.get(name);
|
|
2901
4198
|
if (entry === void 0) {
|
|
2902
4199
|
throw new ToolNotFoundError(name);
|
|
@@ -2910,6 +4207,9 @@ var ToolRegistry = class {
|
|
|
2910
4207
|
if (!await canActorUseTool(ctx.actor, entry.handler)) {
|
|
2911
4208
|
throw new ToolForbiddenError(name);
|
|
2912
4209
|
}
|
|
4210
|
+
if (options.allowedTools !== void 0 && !options.allowedTools.includes(name)) {
|
|
4211
|
+
throw new ToolForbiddenError(name);
|
|
4212
|
+
}
|
|
2913
4213
|
const validation = await entry.spec.inputSchema["~standard"].validate(input);
|
|
2914
4214
|
if (validation.issues !== void 0) {
|
|
2915
4215
|
throw new ToolInputInvalidError(name, validation.issues);
|
|
@@ -2918,7 +4218,11 @@ var ToolRegistry = class {
|
|
|
2918
4218
|
...ctx,
|
|
2919
4219
|
emitUi: createNoopEmitUi(ctx.requestId)
|
|
2920
4220
|
};
|
|
2921
|
-
return
|
|
4221
|
+
return {
|
|
4222
|
+
entry,
|
|
4223
|
+
value: validation.value,
|
|
4224
|
+
ctx: withEmit
|
|
4225
|
+
};
|
|
2922
4226
|
}
|
|
2923
4227
|
};
|
|
2924
4228
|
var DefaultRolesPolicy = class {
|
|
@@ -2965,6 +4269,69 @@ __name(closeEmptyRoles, "closeEmptyRoles");
|
|
|
2965
4269
|
var import_node_crypto = require("crypto");
|
|
2966
4270
|
var import_nestjs_diagnostics2 = require("@dudousxd/nestjs-diagnostics");
|
|
2967
4271
|
|
|
4272
|
+
// src/action-proposal-approval.ts
|
|
4273
|
+
async function resolveActionProposalApproval(input) {
|
|
4274
|
+
const policy = input.policy ?? new DefaultApprovalPolicy();
|
|
4275
|
+
const requirement = await policy.requirementFor(input.tool, input.actor, input.thread);
|
|
4276
|
+
if (!requirement.required) return {
|
|
4277
|
+
mode: "auto"
|
|
4278
|
+
};
|
|
4279
|
+
const remembered = await input.store.rememberedApprovals?.(input.thread.threadId) ?? [];
|
|
4280
|
+
if (remembered.includes(input.tool.name)) return {
|
|
4281
|
+
mode: "remembered",
|
|
4282
|
+
approver: requirement.approver
|
|
4283
|
+
};
|
|
4284
|
+
const roundedTtl = requirement.ttlMs !== void 0 && Number.isFinite(requirement.ttlMs) ? Math.floor(requirement.ttlMs) : 0;
|
|
4285
|
+
if (roundedTtl <= 0) return {
|
|
4286
|
+
mode: "ask",
|
|
4287
|
+
approver: requirement.approver
|
|
4288
|
+
};
|
|
4289
|
+
const now = (input.clock ?? Date.now)();
|
|
4290
|
+
if (!Number.isSafeInteger(now) || !Number.isSafeInteger(roundedTtl) || !Number.isSafeInteger(now + roundedTtl)) throw new RangeError("Invalid action approval deadline");
|
|
4291
|
+
return {
|
|
4292
|
+
mode: "ask",
|
|
4293
|
+
approver: requirement.approver,
|
|
4294
|
+
ttlMs: roundedTtl,
|
|
4295
|
+
expiresAt: new Date(now + roundedTtl).toISOString()
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4298
|
+
__name(resolveActionProposalApproval, "resolveActionProposalApproval");
|
|
4299
|
+
|
|
4300
|
+
// src/action-proposal-preparation.ts
|
|
4301
|
+
async function prepareActionProposal(registry, name, input, ctx, policy, options = {}) {
|
|
4302
|
+
const preparationInput = snapshotActionProposal(input);
|
|
4303
|
+
const prepared = await registry.prepareValidated(name, snapshotActionProposal(preparationInput), ctx, policy, {
|
|
4304
|
+
...options,
|
|
4305
|
+
snapshotInput: true
|
|
4306
|
+
});
|
|
4307
|
+
let replacementKey;
|
|
4308
|
+
const replacement = registry.spec(name)?.replacementKey;
|
|
4309
|
+
if (prepared.preflight.status === "ready" && replacement !== void 0) {
|
|
4310
|
+
replacementKey = typeof replacement === "string" ? replacement : await replacement(snapshotActionProposal(prepared.input), ctx);
|
|
4311
|
+
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");
|
|
4312
|
+
}
|
|
4313
|
+
return {
|
|
4314
|
+
...replacementKey !== void 0 ? {
|
|
4315
|
+
replacementKey
|
|
4316
|
+
} : {},
|
|
4317
|
+
preparationInput,
|
|
4318
|
+
input: prepared.input,
|
|
4319
|
+
// Completed results keep their normal handler contract; they never create a proposal.
|
|
4320
|
+
preflight: prepared.preflight.status === "ready" ? snapshotActionProposal(prepared.preflight) : prepared.preflight
|
|
4321
|
+
};
|
|
4322
|
+
}
|
|
4323
|
+
__name(prepareActionProposal, "prepareActionProposal");
|
|
4324
|
+
|
|
4325
|
+
// src/action-proposal-receipt.ts
|
|
4326
|
+
function actionProposalReceipt(proposalId) {
|
|
4327
|
+
return {
|
|
4328
|
+
proposalId,
|
|
4329
|
+
status: "pending",
|
|
4330
|
+
executed: false
|
|
4331
|
+
};
|
|
4332
|
+
}
|
|
4333
|
+
__name(actionProposalReceipt, "actionProposalReceipt");
|
|
4334
|
+
|
|
2968
4335
|
// src/diagnostics.ts
|
|
2969
4336
|
var import_nestjs_diagnostics = require("@dudousxd/nestjs-diagnostics");
|
|
2970
4337
|
function publishAgentRunStarted(payload) {
|
|
@@ -3040,6 +4407,56 @@ function agentDiagnosticKey(event) {
|
|
|
3040
4407
|
}
|
|
3041
4408
|
__name(agentDiagnosticKey, "agentDiagnosticKey");
|
|
3042
4409
|
|
|
4410
|
+
// src/negotiated-tool-ui.ts
|
|
4411
|
+
function createNegotiatedUiCollector(toolCallId, scope, resolveCatalog, write) {
|
|
4412
|
+
const collector = createUiCollector(toolCallId, write);
|
|
4413
|
+
const texts = /* @__PURE__ */ new Map();
|
|
4414
|
+
let next = 0;
|
|
4415
|
+
return {
|
|
4416
|
+
components: collector.components,
|
|
4417
|
+
text: /* @__PURE__ */ __name(() => [
|
|
4418
|
+
...texts.values()
|
|
4419
|
+
].join("\n"), "text"),
|
|
4420
|
+
restart: /* @__PURE__ */ __name(() => {
|
|
4421
|
+
next = 0;
|
|
4422
|
+
texts.clear();
|
|
4423
|
+
collector.restart();
|
|
4424
|
+
}, "restart"),
|
|
4425
|
+
emit: /* @__PURE__ */ __name(async (component, props, options = {}) => {
|
|
4426
|
+
if (!resolveCatalog) {
|
|
4427
|
+
if (scope.uiCapabilities !== void 0) throw new Error("UI capabilities require an authorized server catalog");
|
|
4428
|
+
return collector.emit(component, props, options);
|
|
4429
|
+
}
|
|
4430
|
+
const capturedProps = snapshotActionProposal(props);
|
|
4431
|
+
const capturedOptions = {
|
|
4432
|
+
...options
|
|
4433
|
+
};
|
|
4434
|
+
const catalog = await resolveCatalog(scope);
|
|
4435
|
+
const prepared = await prepareUiEmission(catalog, scope.uiCapabilities, component, capturedProps, capturedOptions.version);
|
|
4436
|
+
const id = capturedOptions.id ?? `${toolCallId}:ui:${next++}`;
|
|
4437
|
+
if (prepared.kind === "text") {
|
|
4438
|
+
texts.set(id, prepared.text);
|
|
4439
|
+
await write?.({
|
|
4440
|
+
kind: "text",
|
|
4441
|
+
text: prepared.text
|
|
4442
|
+
});
|
|
4443
|
+
return {
|
|
4444
|
+
id
|
|
4445
|
+
};
|
|
4446
|
+
}
|
|
4447
|
+
return collector.emit(prepared.component, prepared.props, {
|
|
4448
|
+
id,
|
|
4449
|
+
version: prepared.version,
|
|
4450
|
+
fallbackText: prepared.fallbackText,
|
|
4451
|
+
...prepared.componentVersions !== void 0 ? {
|
|
4452
|
+
componentVersions: prepared.componentVersions
|
|
4453
|
+
} : {}
|
|
4454
|
+
});
|
|
4455
|
+
}, "emit")
|
|
4456
|
+
};
|
|
4457
|
+
}
|
|
4458
|
+
__name(createNegotiatedUiCollector, "createNegotiatedUiCollector");
|
|
4459
|
+
|
|
3043
4460
|
// src/tool-retry.ts
|
|
3044
4461
|
function hasTransientShape(error) {
|
|
3045
4462
|
if (typeof error !== "object" || error === null) {
|
|
@@ -3065,6 +4482,7 @@ function hasTransientShape(error) {
|
|
|
3065
4482
|
}
|
|
3066
4483
|
__name(hasTransientShape, "hasTransientShape");
|
|
3067
4484
|
function isTransientToolError(error) {
|
|
4485
|
+
if (error instanceof ToolPreflightDeniedError) return false;
|
|
3068
4486
|
if (hasTransientShape(error)) {
|
|
3069
4487
|
return true;
|
|
3070
4488
|
}
|
|
@@ -3107,7 +4525,7 @@ async function invokeWithTransientRetry(fn, setting, options) {
|
|
|
3107
4525
|
try {
|
|
3108
4526
|
return await fn();
|
|
3109
4527
|
} catch (error) {
|
|
3110
|
-
if (isControlFlowSignal(error) || options?.isControlFlowError?.(error) === true) {
|
|
4528
|
+
if (error instanceof ToolPreflightDeniedError || isControlFlowSignal(error) || options?.isControlFlowError?.(error) === true) {
|
|
3111
4529
|
throw error;
|
|
3112
4530
|
}
|
|
3113
4531
|
const attemptsRemain = attempt < attempts;
|
|
@@ -3261,16 +4679,10 @@ async function resolvePrompt(prompt, ctx) {
|
|
|
3261
4679
|
return typeof prompt === "function" ? prompt(ctx) : prompt;
|
|
3262
4680
|
}
|
|
3263
4681
|
__name(resolvePrompt, "resolvePrompt");
|
|
3264
|
-
async function resolveSystemPrompt(deps, input) {
|
|
3265
|
-
const ctx =
|
|
3266
|
-
actor: input.actor,
|
|
3267
|
-
agentName: input.agentName ?? "default",
|
|
3268
|
-
...input.pageContext !== void 0 ? {
|
|
3269
|
-
pageContext: input.pageContext
|
|
3270
|
-
} : {}
|
|
3271
|
-
};
|
|
4682
|
+
async function resolveSystemPrompt(deps, input, persona) {
|
|
4683
|
+
const ctx = promptContext(input, persona);
|
|
3272
4684
|
const sections = [
|
|
3273
|
-
await resolvePrompt(deps.systemPrompt, ctx)
|
|
4685
|
+
persona?.prompt ?? await resolvePrompt(deps.systemPrompt, ctx)
|
|
3274
4686
|
];
|
|
3275
4687
|
for (const contribute of deps.promptContributors ?? []) {
|
|
3276
4688
|
const section = await contribute(ctx);
|
|
@@ -3281,6 +4693,70 @@ async function resolveSystemPrompt(deps, input) {
|
|
|
3281
4693
|
return sections.join("\n\n");
|
|
3282
4694
|
}
|
|
3283
4695
|
__name(resolveSystemPrompt, "resolveSystemPrompt");
|
|
4696
|
+
function withoutPersona(input) {
|
|
4697
|
+
const { persona: _dropped, ...rest } = input;
|
|
4698
|
+
return rest;
|
|
4699
|
+
}
|
|
4700
|
+
__name(withoutPersona, "withoutPersona");
|
|
4701
|
+
function promptContext(input, persona) {
|
|
4702
|
+
return {
|
|
4703
|
+
actor: input.actor,
|
|
4704
|
+
agentName: input.agentName ?? "default",
|
|
4705
|
+
...input.pageContext !== void 0 ? {
|
|
4706
|
+
pageContext: input.pageContext
|
|
4707
|
+
} : {},
|
|
4708
|
+
...input.uiCapabilities !== void 0 ? {
|
|
4709
|
+
uiCapabilities: input.uiCapabilities
|
|
4710
|
+
} : {},
|
|
4711
|
+
...persona !== void 0 ? {
|
|
4712
|
+
persona: {
|
|
4713
|
+
id: persona.id,
|
|
4714
|
+
label: persona.label
|
|
4715
|
+
}
|
|
4716
|
+
} : {}
|
|
4717
|
+
};
|
|
4718
|
+
}
|
|
4719
|
+
__name(promptContext, "promptContext");
|
|
4720
|
+
async function resolveTurnPersona(deps, input) {
|
|
4721
|
+
const persona = findPersona(deps, input.persona);
|
|
4722
|
+
if (persona === void 0) {
|
|
4723
|
+
return null;
|
|
4724
|
+
}
|
|
4725
|
+
const ref = {
|
|
4726
|
+
id: persona.id,
|
|
4727
|
+
label: persona.label
|
|
4728
|
+
};
|
|
4729
|
+
let prompt;
|
|
4730
|
+
if (persona.systemPrompt !== void 0) {
|
|
4731
|
+
const ctx = promptContext(input, ref);
|
|
4732
|
+
const basePrompt = typeof persona.systemPrompt === "function" ? await resolvePrompt(deps.systemPrompt, ctx) : void 0;
|
|
4733
|
+
prompt = await resolvePrompt(persona.systemPrompt, {
|
|
4734
|
+
...ctx,
|
|
4735
|
+
...basePrompt !== void 0 ? {
|
|
4736
|
+
basePrompt
|
|
4737
|
+
} : {}
|
|
4738
|
+
});
|
|
4739
|
+
}
|
|
4740
|
+
return {
|
|
4741
|
+
...ref,
|
|
4742
|
+
...persona.allowedTools !== void 0 ? {
|
|
4743
|
+
allowedTools: [
|
|
4744
|
+
...persona.allowedTools
|
|
4745
|
+
]
|
|
4746
|
+
} : {},
|
|
4747
|
+
...prompt !== void 0 ? {
|
|
4748
|
+
prompt
|
|
4749
|
+
} : {}
|
|
4750
|
+
};
|
|
4751
|
+
}
|
|
4752
|
+
__name(resolveTurnPersona, "resolveTurnPersona");
|
|
4753
|
+
function personaRefusal(persona, toolName) {
|
|
4754
|
+
if (persona?.allowedTools === void 0 || persona.allowedTools.includes(toolName)) {
|
|
4755
|
+
return null;
|
|
4756
|
+
}
|
|
4757
|
+
return `(tool "${toolName}" is not available to the "${persona.id}" persona)`;
|
|
4758
|
+
}
|
|
4759
|
+
__name(personaRefusal, "personaRefusal");
|
|
3284
4760
|
function extractTask(input) {
|
|
3285
4761
|
if (typeof input === "object" && input !== null && "task" in input) {
|
|
3286
4762
|
const task = input.task;
|
|
@@ -3428,7 +4904,8 @@ async function loadSelectedHistory(deps, input, hooks) {
|
|
|
3428
4904
|
messages: keep,
|
|
3429
4905
|
dropped: deps.historyPolicy?.summarize === void 0 ? [] : drop,
|
|
3430
4906
|
title: thread.title,
|
|
3431
|
-
hasAssistantMessage: thread.hasAssistantMessage
|
|
4907
|
+
hasAssistantMessage: thread.hasAssistantMessage,
|
|
4908
|
+
actionApprovalMode: deps.actionApprovalMode ?? "blocking"
|
|
3432
4909
|
};
|
|
3433
4910
|
});
|
|
3434
4911
|
return {
|
|
@@ -3522,6 +4999,9 @@ function processorContext(input, step) {
|
|
|
3522
4999
|
step,
|
|
3523
5000
|
...input.agentName !== void 0 ? {
|
|
3524
5001
|
agentName: input.agentName
|
|
5002
|
+
} : {},
|
|
5003
|
+
...input.persona !== void 0 ? {
|
|
5004
|
+
persona: input.persona
|
|
3525
5005
|
} : {}
|
|
3526
5006
|
};
|
|
3527
5007
|
}
|
|
@@ -3589,10 +5069,10 @@ async function structureAnswer(schema, deps, input, hooks, messages, step) {
|
|
|
3589
5069
|
modelId: turn.modelId
|
|
3590
5070
|
} : {}
|
|
3591
5071
|
};
|
|
3592
|
-
}, (
|
|
3593
|
-
inputTokens:
|
|
3594
|
-
outputTokens:
|
|
3595
|
-
textLength:
|
|
5072
|
+
}, (result2) => ({
|
|
5073
|
+
inputTokens: result2.usage.inputTokens,
|
|
5074
|
+
outputTokens: result2.usage.outputTokens,
|
|
5075
|
+
textLength: result2.text.length
|
|
3596
5076
|
})));
|
|
3597
5077
|
await hooks.step(`persist:usage:structured:${step}:${attempt}`, () => deps.store.recordUsage({
|
|
3598
5078
|
threadId: input.threadId,
|
|
@@ -3622,13 +5102,16 @@ async function structureAnswer(schema, deps, input, hooks, messages, step) {
|
|
|
3622
5102
|
throw new StructuredOutputError(issues, text, maxAttempts);
|
|
3623
5103
|
}
|
|
3624
5104
|
__name(structureAnswer, "structureAnswer");
|
|
3625
|
-
function stampToolKinds(
|
|
5105
|
+
function stampToolKinds(result2, deps) {
|
|
3626
5106
|
return {
|
|
3627
|
-
...
|
|
3628
|
-
toolCalls:
|
|
3629
|
-
...call
|
|
3630
|
-
kind
|
|
3631
|
-
|
|
5107
|
+
...result2,
|
|
5108
|
+
toolCalls: result2.toolCalls.map((call) => {
|
|
5109
|
+
const { preflight: _untrusted, prepared: _untrustedPrepared, actionApproval: _untrustedApproval, ...trusted } = call;
|
|
5110
|
+
return trusted.kind === void 0 ? {
|
|
5111
|
+
...trusted,
|
|
5112
|
+
kind: declaredKind(deps, trusted.name)
|
|
5113
|
+
} : trusted;
|
|
5114
|
+
})
|
|
3632
5115
|
};
|
|
3633
5116
|
}
|
|
3634
5117
|
__name(stampToolKinds, "stampToolKinds");
|
|
@@ -3685,9 +5168,15 @@ function toolContext(deps, input, hooks) {
|
|
|
3685
5168
|
...input.agentName !== void 0 ? {
|
|
3686
5169
|
agentName: input.agentName
|
|
3687
5170
|
} : {},
|
|
5171
|
+
...input.persona !== void 0 ? {
|
|
5172
|
+
persona: input.persona
|
|
5173
|
+
} : {},
|
|
3688
5174
|
...input.pageContext !== void 0 ? {
|
|
3689
5175
|
pageContext: input.pageContext
|
|
3690
5176
|
} : {},
|
|
5177
|
+
...input.uiCapabilities !== void 0 ? {
|
|
5178
|
+
uiCapabilities: input.uiCapabilities
|
|
5179
|
+
} : {},
|
|
3691
5180
|
...deps.host !== void 0 ? {
|
|
3692
5181
|
host: deps.host
|
|
3693
5182
|
} : {},
|
|
@@ -3732,6 +5221,9 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3732
5221
|
],
|
|
3733
5222
|
...input.agentName !== void 0 ? {
|
|
3734
5223
|
agentName: input.agentName
|
|
5224
|
+
} : {},
|
|
5225
|
+
...input.persona !== void 0 ? {
|
|
5226
|
+
persona: input.persona
|
|
3735
5227
|
} : {}
|
|
3736
5228
|
});
|
|
3737
5229
|
await deps.store.recordToolCall({
|
|
@@ -3760,16 +5252,16 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3760
5252
|
}
|
|
3761
5253
|
const messageId = asked.messageId;
|
|
3762
5254
|
const reply = await awaitElicitation(hooks, request, toolContext(deps, input, hooks));
|
|
3763
|
-
const
|
|
5255
|
+
const result2 = settleElicitation(request, reply);
|
|
3764
5256
|
await hooks.step("intake:answers", async () => {
|
|
3765
5257
|
await deps.store.updateToolCall({
|
|
3766
5258
|
toolCallId: request.id,
|
|
3767
5259
|
// A skip is not an answer. Both leave the agent holding the same values, but only one of them
|
|
3768
5260
|
// is evidence the user chose them, and a reader auditing what the agent was told has to be
|
|
3769
5261
|
// able to tell those apart.
|
|
3770
|
-
status:
|
|
3771
|
-
output:
|
|
3772
|
-
...
|
|
5262
|
+
status: result2.skipped ? "rejected" : "executed",
|
|
5263
|
+
output: result2,
|
|
5264
|
+
...result2.skipped ? {
|
|
3773
5265
|
error: "skipped by the user"
|
|
3774
5266
|
} : {},
|
|
3775
5267
|
...reply.answeredByRef !== void 0 ? {
|
|
@@ -3780,13 +5272,13 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3780
5272
|
{
|
|
3781
5273
|
id: request.id,
|
|
3782
5274
|
name: ASK_TOOL_NAME,
|
|
3783
|
-
output:
|
|
5275
|
+
output: result2
|
|
3784
5276
|
}
|
|
3785
5277
|
]);
|
|
3786
5278
|
await writer.write(encodeStreamEvent({
|
|
3787
5279
|
kind: "tool-output",
|
|
3788
5280
|
id: request.id,
|
|
3789
|
-
output:
|
|
5281
|
+
output: result2
|
|
3790
5282
|
}));
|
|
3791
5283
|
});
|
|
3792
5284
|
return {
|
|
@@ -3799,7 +5291,7 @@ async function runIntake(intake, deps, input, hooks, writer, threadHasAssistant)
|
|
|
3799
5291
|
{
|
|
3800
5292
|
id: request.id,
|
|
3801
5293
|
name: ASK_TOOL_NAME,
|
|
3802
|
-
output:
|
|
5294
|
+
output: result2
|
|
3803
5295
|
}
|
|
3804
5296
|
]
|
|
3805
5297
|
};
|
|
@@ -3845,16 +5337,140 @@ async function claimToolCall(turn, call) {
|
|
|
3845
5337
|
const spec = deps.registry.spec(call.name);
|
|
3846
5338
|
const kind = call.kind ?? declaredKind(deps, call.name);
|
|
3847
5339
|
const awaitsHuman = kind === "action" || kind === "ask";
|
|
3848
|
-
const
|
|
3849
|
-
|
|
5340
|
+
const independentApproval = turn.actionApprovalMode === "independent" && kind === "action" ? hooks.dispatchLlm !== void 0 && call.actionApproval !== void 0 ? call.actionApproval : await resolveActionProposalApproval({
|
|
5341
|
+
actor: input.actor,
|
|
5342
|
+
store: deps.store,
|
|
5343
|
+
tool: {
|
|
5344
|
+
name: call.name,
|
|
5345
|
+
kind: "action",
|
|
5346
|
+
...spec !== void 0 ? {
|
|
5347
|
+
spec
|
|
5348
|
+
} : {}
|
|
5349
|
+
},
|
|
5350
|
+
thread: {
|
|
5351
|
+
threadId: input.threadId,
|
|
5352
|
+
runId: hooks.runId,
|
|
5353
|
+
...input.agentName !== void 0 ? {
|
|
5354
|
+
agentName: input.agentName
|
|
5355
|
+
} : {}
|
|
5356
|
+
},
|
|
5357
|
+
...deps.approvalPolicy !== void 0 ? {
|
|
5358
|
+
policy: deps.approvalPolicy
|
|
5359
|
+
} : {}
|
|
5360
|
+
}) : void 0;
|
|
5361
|
+
let preflight;
|
|
5362
|
+
let prepared;
|
|
5363
|
+
if (turn.actionApprovalMode === "independent" && call.prepared !== void 0 && hooks.dispatchLlm !== void 0) prepared = call.prepared;
|
|
5364
|
+
if (kind === "action" && hooks.dispatchLlm !== void 0 && call.preflight !== void 0) {
|
|
5365
|
+
preflight = call.preflight;
|
|
5366
|
+
} else if (kind === "action" && hooks.dispatchLlm !== void 0 && spec === void 0) {
|
|
5367
|
+
preflight = {
|
|
5368
|
+
status: "ready"
|
|
5369
|
+
};
|
|
5370
|
+
} else if (kind === "action") {
|
|
5371
|
+
try {
|
|
5372
|
+
const allowedTools = turn.persona?.allowedTools === void 0 ? deps.toolAllowList : intersectAllowLists(deps.toolAllowList, turn.persona.allowedTools);
|
|
5373
|
+
if (independentApproval?.mode === "ask") {
|
|
5374
|
+
prepared = await prepareActionProposal(deps.registry, call.name, call.input, toolCallContext(toolContext(deps, input, hooks), call.id), deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
5375
|
+
allowedTools
|
|
5376
|
+
});
|
|
5377
|
+
preflight = prepared.preflight;
|
|
5378
|
+
} else {
|
|
5379
|
+
preflight = await deps.registry.prepare(call.name, call.input, toolCallContext(toolContext(deps, input, hooks), call.id), deps.rolesPolicy, allowedTools === void 0 ? {} : {
|
|
5380
|
+
allowedTools
|
|
5381
|
+
});
|
|
5382
|
+
}
|
|
5383
|
+
} catch (error) {
|
|
5384
|
+
if (hooks.isControlFlowError?.(error) === true || isControlFlowSignal(error) || isReplayIntegrityError(error)) throw error;
|
|
5385
|
+
preflight = {
|
|
5386
|
+
status: "failed",
|
|
5387
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5388
|
+
};
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
let confirmation = preflight?.status === "ready" ? preflight.confirmation : void 0;
|
|
5392
|
+
const approval = kind === "action" && preflight?.status === "ready" ? independentApproval ?? await claimApproval(turn, call, spec) : void 0;
|
|
5393
|
+
let proposalId;
|
|
5394
|
+
if (turn.actionApprovalMode === "independent" && approval?.mode === "ask") {
|
|
5395
|
+
if (!prepared) throw new Error("Independent action lacks trusted prepared input");
|
|
5396
|
+
const proposalStore = deps.store;
|
|
5397
|
+
if (typeof proposalStore.createActionProposal !== "function") throw new Error("Independent action proposal store unavailable");
|
|
5398
|
+
proposalId = `proposal-${(0, import_node_crypto.createHash)("sha256").update(JSON.stringify([
|
|
5399
|
+
hooks.runId,
|
|
5400
|
+
call.id
|
|
5401
|
+
])).digest("hex")}`;
|
|
5402
|
+
const display = confirmation ?? spec?.presentation?.confirm ?? {
|
|
5403
|
+
title: `Allow ${call.name}?`,
|
|
5404
|
+
verb: "Approve"
|
|
5405
|
+
};
|
|
5406
|
+
const fill = /* @__PURE__ */ __name((value) => value.replace(/\{([^}]+)\}/g, (_match, path) => {
|
|
5407
|
+
let current = prepared?.input;
|
|
5408
|
+
for (const part of path.split(".")) current = current !== null && typeof current === "object" ? current[part] : void 0;
|
|
5409
|
+
return current === void 0 ? "" : String(current);
|
|
5410
|
+
}), "fill");
|
|
5411
|
+
const create = prepared.replacementKey === void 0 ? proposalStore.createActionProposal.bind(proposalStore) : (() => {
|
|
5412
|
+
const store = proposalStore;
|
|
5413
|
+
if (typeof store.createReplacingActionProposal !== "function") throw new Error("Independent replacement requires atomic supersession store");
|
|
5414
|
+
return store.createReplacingActionProposal.bind(store);
|
|
5415
|
+
})();
|
|
5416
|
+
const created = await create({
|
|
5417
|
+
...prepared.replacementKey !== void 0 ? {
|
|
5418
|
+
replacementKey: prepared.replacementKey
|
|
5419
|
+
} : {},
|
|
5420
|
+
id: proposalId,
|
|
5421
|
+
tenantRef: input.actor.tenantRef ?? null,
|
|
5422
|
+
actorRef: input.actor.id,
|
|
5423
|
+
threadId: input.threadId,
|
|
5424
|
+
originRunId: hooks.runId,
|
|
5425
|
+
originMessageId: messageId,
|
|
5426
|
+
originToolCallId: call.id,
|
|
5427
|
+
toolName: call.name,
|
|
5428
|
+
input: prepared.input,
|
|
5429
|
+
preparationInput: prepared.preparationInput,
|
|
5430
|
+
executionContext: {
|
|
5431
|
+
requestId: hooks.runId,
|
|
5432
|
+
...input.agentName !== void 0 ? {
|
|
5433
|
+
agentName: input.agentName
|
|
5434
|
+
} : {},
|
|
5435
|
+
...input.persona !== void 0 ? {
|
|
5436
|
+
persona: input.persona
|
|
5437
|
+
} : {},
|
|
5438
|
+
...input.pageContext !== void 0 ? {
|
|
5439
|
+
pageContext: input.pageContext
|
|
5440
|
+
} : {},
|
|
5441
|
+
...input.uiCapabilities !== void 0 ? {
|
|
5442
|
+
uiCapabilities: input.uiCapabilities
|
|
5443
|
+
} : {}
|
|
5444
|
+
},
|
|
5445
|
+
confirmation: confirmation ?? {
|
|
5446
|
+
title: fill(display.title),
|
|
5447
|
+
verb: fill(display.verb),
|
|
5448
|
+
...display.detail !== void 0 ? {
|
|
5449
|
+
detail: fill(display.detail)
|
|
5450
|
+
} : {}
|
|
5451
|
+
},
|
|
5452
|
+
approver: approval.approver,
|
|
5453
|
+
expiresAt: approval.expiresAt === void 0 ? null : Date.parse(approval.expiresAt),
|
|
5454
|
+
idempotencyKey: toolCallContext(toolContext(deps, input, hooks), call.id).idempotencyKey
|
|
5455
|
+
});
|
|
5456
|
+
if (created.status === "conflict") throw new Error("Action proposal replay payload conflict");
|
|
5457
|
+
confirmation = created.proposal?.confirmation ?? confirmation;
|
|
5458
|
+
}
|
|
5459
|
+
const parks = kind === "ask" || approval?.mode === "ask" && proposalId === void 0;
|
|
3850
5460
|
await deps.store.recordToolCall({
|
|
3851
5461
|
toolCallId: call.id,
|
|
3852
5462
|
messageId,
|
|
3853
5463
|
toolName: call.name,
|
|
3854
5464
|
toolType: awaitsHuman ? "action" : "read",
|
|
3855
5465
|
input: call.input,
|
|
3856
|
-
status: parks ? "pending_approval" : "auto_executed",
|
|
5466
|
+
status: proposalId !== void 0 ? "proposed" : parks ? "pending_approval" : "auto_executed",
|
|
5467
|
+
...proposalId !== void 0 ? {
|
|
5468
|
+
proposalId
|
|
5469
|
+
} : {},
|
|
3857
5470
|
runId: hooks.runId,
|
|
5471
|
+
...confirmation !== void 0 ? {
|
|
5472
|
+
confirmation
|
|
5473
|
+
} : {},
|
|
3858
5474
|
...approval !== void 0 && approval.mode !== "auto" ? {
|
|
3859
5475
|
approver: approval.approver
|
|
3860
5476
|
} : {},
|
|
@@ -3866,7 +5482,16 @@ async function claimToolCall(turn, call) {
|
|
|
3866
5482
|
await turn.writer.write(encodeStreamEvent({
|
|
3867
5483
|
kind: "approval-requested",
|
|
3868
5484
|
id: call.id,
|
|
5485
|
+
...proposalId !== void 0 ? {
|
|
5486
|
+
target: {
|
|
5487
|
+
kind: "proposal",
|
|
5488
|
+
proposalId
|
|
5489
|
+
}
|
|
5490
|
+
} : {},
|
|
3869
5491
|
approver: approval.approver,
|
|
5492
|
+
...confirmation !== void 0 ? {
|
|
5493
|
+
confirmation
|
|
5494
|
+
} : {},
|
|
3870
5495
|
...approval.expiresAt !== void 0 ? {
|
|
3871
5496
|
expiresAt: approval.expiresAt
|
|
3872
5497
|
} : {}
|
|
@@ -3889,6 +5514,12 @@ async function claimToolCall(turn, call) {
|
|
|
3889
5514
|
} : {},
|
|
3890
5515
|
...approval !== void 0 ? {
|
|
3891
5516
|
approval
|
|
5517
|
+
} : {},
|
|
5518
|
+
...preflight !== void 0 ? {
|
|
5519
|
+
preflight
|
|
5520
|
+
} : {},
|
|
5521
|
+
...proposalId !== void 0 ? {
|
|
5522
|
+
proposalId
|
|
3892
5523
|
} : {}
|
|
3893
5524
|
};
|
|
3894
5525
|
});
|
|
@@ -3914,6 +5545,12 @@ async function claimToolCall(turn, call) {
|
|
|
3914
5545
|
...toolType === "action" && persisted?.approval !== void 0 ? {
|
|
3915
5546
|
approval: persisted.approval
|
|
3916
5547
|
} : {},
|
|
5548
|
+
...persisted?.preflight !== void 0 ? {
|
|
5549
|
+
preflight: persisted.preflight
|
|
5550
|
+
} : {},
|
|
5551
|
+
...persisted?.proposalId !== void 0 ? {
|
|
5552
|
+
proposalId: persisted.proposalId
|
|
5553
|
+
} : {},
|
|
3917
5554
|
ctx: toolContext(deps, input, hooks)
|
|
3918
5555
|
};
|
|
3919
5556
|
}
|
|
@@ -4061,6 +5698,9 @@ function skillContext(input) {
|
|
|
4061
5698
|
} : {},
|
|
4062
5699
|
...input.pageContext !== void 0 ? {
|
|
4063
5700
|
pageContext: input.pageContext
|
|
5701
|
+
} : {},
|
|
5702
|
+
...input.uiCapabilities !== void 0 ? {
|
|
5703
|
+
uiCapabilities: input.uiCapabilities
|
|
4064
5704
|
} : {}
|
|
4065
5705
|
};
|
|
4066
5706
|
}
|
|
@@ -4077,6 +5717,7 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4077
5717
|
if (claimed.toolType === "memory") {
|
|
4078
5718
|
return await rememberIntoTurn(turn, claimed, startedAt);
|
|
4079
5719
|
}
|
|
5720
|
+
const invokeAllowList = turn.persona?.allowedTools === void 0 ? deps.toolAllowList : intersectAllowLists(deps.toolAllowList, turn.persona.allowedTools);
|
|
4080
5721
|
let raw;
|
|
4081
5722
|
if (hooks.dispatchTool) {
|
|
4082
5723
|
const stepCtx = {
|
|
@@ -4087,14 +5728,23 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4087
5728
|
...input.agentName !== void 0 ? {
|
|
4088
5729
|
agentName: input.agentName
|
|
4089
5730
|
} : {},
|
|
5731
|
+
...input.persona !== void 0 ? {
|
|
5732
|
+
persona: input.persona
|
|
5733
|
+
} : {},
|
|
4090
5734
|
...input.pageContext !== void 0 ? {
|
|
4091
5735
|
pageContext: input.pageContext
|
|
5736
|
+
} : {},
|
|
5737
|
+
...input.uiCapabilities !== void 0 ? {
|
|
5738
|
+
uiCapabilities: input.uiCapabilities
|
|
4092
5739
|
} : {}
|
|
4093
5740
|
};
|
|
4094
5741
|
const envelope = {
|
|
4095
5742
|
toolName: call.name,
|
|
4096
5743
|
input: call.input,
|
|
4097
5744
|
ctx: stepCtx,
|
|
5745
|
+
...invokeAllowList !== void 0 ? {
|
|
5746
|
+
allowedTools: invokeAllowList
|
|
5747
|
+
} : {},
|
|
4098
5748
|
...deps.toolTimeoutMs !== void 0 ? {
|
|
4099
5749
|
timeoutMs: deps.toolTimeoutMs
|
|
4100
5750
|
} : {},
|
|
@@ -4107,35 +5757,49 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4107
5757
|
raw = await hooks.dispatchTool(resolvedCall, envelope);
|
|
4108
5758
|
} else {
|
|
4109
5759
|
const invocation = hooks.step(`tool:${call.id}`, async () => {
|
|
4110
|
-
const ui2 =
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
5760
|
+
const ui2 = createNegotiatedUiCollector(call.id, ctx, deps.resolveUiCatalog, (event) => turn.writer.write(encodeStreamEvent(event)));
|
|
5761
|
+
let output2;
|
|
5762
|
+
try {
|
|
5763
|
+
output2 = await traceToolExecution(hooks.runId, {
|
|
5764
|
+
toolCallId: call.id,
|
|
5765
|
+
toolName: call.name,
|
|
5766
|
+
toolType
|
|
5767
|
+
}, () => invokeWithTransientRetry(() => {
|
|
5768
|
+
ui2.restart();
|
|
5769
|
+
return deps.registry.invoke(call.name, call.input, {
|
|
5770
|
+
...toolCallContext(ctx, call.id),
|
|
5771
|
+
emitUi: ui2.emit
|
|
5772
|
+
}, deps.rolesPolicy, invokeAllowList !== void 0 ? {
|
|
5773
|
+
allowedTools: invokeAllowList
|
|
5774
|
+
} : {});
|
|
5775
|
+
}, deps.toolTransientRetry ?? {}, {
|
|
5776
|
+
...hooks.isControlFlowError !== void 0 ? {
|
|
5777
|
+
isControlFlowError: hooks.isControlFlowError
|
|
5778
|
+
} : {},
|
|
5779
|
+
onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
|
|
5780
|
+
publishAgentToolRetry({
|
|
5781
|
+
toolName: call.name,
|
|
5782
|
+
toolCallId: call.id,
|
|
5783
|
+
attempt,
|
|
5784
|
+
message: retryError instanceof Error ? retryError.message : String(retryError)
|
|
5785
|
+
});
|
|
5786
|
+
}, "onRetry")
|
|
5787
|
+
}));
|
|
5788
|
+
} catch (error) {
|
|
5789
|
+
if (error instanceof Error && error.name === "ToolPreflightDeniedError") return wrapToolPreflightDenied(error.message);
|
|
5790
|
+
throw error;
|
|
5791
|
+
}
|
|
5792
|
+
return wrapToolStepOutput(output2, ui2.components(), ui2.text());
|
|
4135
5793
|
});
|
|
4136
5794
|
raw = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
|
|
4137
5795
|
}
|
|
4138
|
-
const { output, ui } = unwrapToolStepOutput(raw);
|
|
5796
|
+
const { output, ui, preflightDenied, text } = unwrapToolStepOutput(raw);
|
|
5797
|
+
if (text) turn.toolText.set(call.id, text);
|
|
5798
|
+
if (preflightDenied !== void 0) return {
|
|
5799
|
+
status: "denied",
|
|
5800
|
+
reason: preflightDenied,
|
|
5801
|
+
executionMs: Date.now() - startedAt
|
|
5802
|
+
};
|
|
4139
5803
|
if (ui.length > 0) {
|
|
4140
5804
|
turn.toolUi.set(call.id, ui);
|
|
4141
5805
|
}
|
|
@@ -4151,6 +5815,13 @@ async function invokeClaimedTool(turn, claimed) {
|
|
|
4151
5815
|
if (hooks.isControlFlowError?.(error) === true || isControlFlowSignal(error) || isReplayIntegrityError(error)) {
|
|
4152
5816
|
throw error;
|
|
4153
5817
|
}
|
|
5818
|
+
if (error instanceof Error && error.name === "ToolPreflightDeniedError") {
|
|
5819
|
+
return {
|
|
5820
|
+
status: "denied",
|
|
5821
|
+
reason: error.message,
|
|
5822
|
+
executionMs: Date.now() - startedAt
|
|
5823
|
+
};
|
|
5824
|
+
}
|
|
4154
5825
|
return {
|
|
4155
5826
|
status: "failed",
|
|
4156
5827
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -4192,6 +5863,27 @@ async function recordToolOutcome(turn, claimed, outcome, deciderRef, meta) {
|
|
|
4192
5863
|
} : {}
|
|
4193
5864
|
}));
|
|
4194
5865
|
}, "settle");
|
|
5866
|
+
if (outcome.status === "denied") {
|
|
5867
|
+
await hooks.step(`persist:toolreject:${call.id}`, async () => {
|
|
5868
|
+
await deps.store.updateToolCall({
|
|
5869
|
+
toolCallId: call.id,
|
|
5870
|
+
status: meta === void 0 ? "rejected" : "failed",
|
|
5871
|
+
error: outcome.reason,
|
|
5872
|
+
...decided
|
|
5873
|
+
});
|
|
5874
|
+
await settle();
|
|
5875
|
+
});
|
|
5876
|
+
return {
|
|
5877
|
+
id: call.id,
|
|
5878
|
+
name: call.name,
|
|
5879
|
+
output: {
|
|
5880
|
+
rejected: true,
|
|
5881
|
+
reason: outcome.reason
|
|
5882
|
+
},
|
|
5883
|
+
denied: true,
|
|
5884
|
+
error: `This action was denied by its preflight check: ${outcome.reason}. The requested mutation did not run.`
|
|
5885
|
+
};
|
|
5886
|
+
}
|
|
4195
5887
|
if (outcome.status === "failed") {
|
|
4196
5888
|
await hooks.step(`persist:toolfail:${call.id}`, async () => {
|
|
4197
5889
|
await deps.store.updateToolCall({
|
|
@@ -4248,7 +5940,7 @@ async function delegateToolCall(turn, claimed) {
|
|
|
4248
5940
|
const { deps, input, hooks } = turn;
|
|
4249
5941
|
const { call, targetAgent = call.name } = claimed;
|
|
4250
5942
|
const task = extractTask(call.input);
|
|
4251
|
-
const refusal = delegationRefusal({
|
|
5943
|
+
const refusal = personaRefusal(turn.persona, call.name) ?? delegationRefusal({
|
|
4252
5944
|
deps,
|
|
4253
5945
|
input,
|
|
4254
5946
|
targetAgent
|
|
@@ -4332,12 +6024,12 @@ async function elicitToolCall(turn, claimed) {
|
|
|
4332
6024
|
}));
|
|
4333
6025
|
});
|
|
4334
6026
|
const reply = await awaitElicitation(hooks, request, ctx);
|
|
4335
|
-
const
|
|
4336
|
-
await hooks.step(
|
|
6027
|
+
const result2 = settleElicitation(request, reply);
|
|
6028
|
+
await hooks.step(result2.skipped ? `persist:toolreject:${call.id}` : `persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
|
|
4337
6029
|
toolCallId: call.id,
|
|
4338
|
-
status:
|
|
4339
|
-
output:
|
|
4340
|
-
...
|
|
6030
|
+
status: result2.skipped ? "rejected" : "executed",
|
|
6031
|
+
output: result2,
|
|
6032
|
+
...result2.skipped ? {
|
|
4341
6033
|
error: "skipped by the user"
|
|
4342
6034
|
} : {},
|
|
4343
6035
|
...reply.answeredByRef !== void 0 ? {
|
|
@@ -4348,24 +6040,50 @@ async function elicitToolCall(turn, claimed) {
|
|
|
4348
6040
|
runId: hooks.runId,
|
|
4349
6041
|
toolName: call.name,
|
|
4350
6042
|
toolType: "action",
|
|
4351
|
-
status:
|
|
6043
|
+
status: result2.skipped ? "rejected" : "executed"
|
|
4352
6044
|
});
|
|
4353
6045
|
return {
|
|
4354
6046
|
id: call.id,
|
|
4355
6047
|
name: call.name,
|
|
4356
|
-
output:
|
|
6048
|
+
output: result2
|
|
4357
6049
|
};
|
|
4358
6050
|
}
|
|
4359
6051
|
__name(elicitToolCall, "elicitToolCall");
|
|
4360
6052
|
async function runClaimedToolCall(turn, claimed) {
|
|
4361
6053
|
const { deps, input, hooks } = turn;
|
|
4362
6054
|
const { call, toolType, ctx } = claimed;
|
|
6055
|
+
if (claimed.proposalId !== void 0) {
|
|
6056
|
+
turn.halt.independentProposal = true;
|
|
6057
|
+
return {
|
|
6058
|
+
id: call.id,
|
|
6059
|
+
name: call.name,
|
|
6060
|
+
output: actionProposalReceipt(claimed.proposalId)
|
|
6061
|
+
};
|
|
6062
|
+
}
|
|
4363
6063
|
if (toolType === "agent") {
|
|
4364
6064
|
return delegateToolCall(turn, claimed);
|
|
4365
6065
|
}
|
|
4366
6066
|
if (toolType === "ask") {
|
|
4367
6067
|
return elicitToolCall(turn, claimed);
|
|
4368
6068
|
}
|
|
6069
|
+
if (claimed.preflight !== void 0 && claimed.preflight.status !== "ready") {
|
|
6070
|
+
const result2 = claimed.preflight;
|
|
6071
|
+
if (result2.status === "completed" && claimed.terminal === true) turn.halt.terminal = true;
|
|
6072
|
+
const outcome = result2.status === "completed" ? {
|
|
6073
|
+
status: "executed",
|
|
6074
|
+
output: result2.output,
|
|
6075
|
+
executionMs: 0
|
|
6076
|
+
} : result2.status === "denied" ? {
|
|
6077
|
+
status: "denied",
|
|
6078
|
+
reason: result2.reason,
|
|
6079
|
+
executionMs: 0
|
|
6080
|
+
} : {
|
|
6081
|
+
status: "failed",
|
|
6082
|
+
error: result2.error,
|
|
6083
|
+
executionMs: 0
|
|
6084
|
+
};
|
|
6085
|
+
return recordToolOutcome(turn, claimed, outcome, input.actor.id);
|
|
6086
|
+
}
|
|
4369
6087
|
let deciderRef = input.actor.id;
|
|
4370
6088
|
let meta;
|
|
4371
6089
|
if (toolType === "action" && claimed.approval?.mode === "remembered") {
|
|
@@ -4490,30 +6208,30 @@ function expiryNarrative() {
|
|
|
4490
6208
|
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.";
|
|
4491
6209
|
}
|
|
4492
6210
|
__name(expiryNarrative, "expiryNarrative");
|
|
4493
|
-
function outputFrame(
|
|
4494
|
-
if (
|
|
4495
|
-
const reason = refusalReason(
|
|
6211
|
+
function outputFrame(result2) {
|
|
6212
|
+
if (result2.denied === true) {
|
|
6213
|
+
const reason = refusalReason(result2);
|
|
4496
6214
|
return {
|
|
4497
6215
|
kind: "tool-output-denied",
|
|
4498
|
-
id:
|
|
6216
|
+
id: result2.id,
|
|
4499
6217
|
...reason !== void 0 ? {
|
|
4500
6218
|
reason
|
|
4501
6219
|
} : {}
|
|
4502
6220
|
};
|
|
4503
6221
|
}
|
|
4504
|
-
return
|
|
6222
|
+
return result2.error !== void 0 ? {
|
|
4505
6223
|
kind: "tool-output-error",
|
|
4506
|
-
id:
|
|
4507
|
-
error:
|
|
6224
|
+
id: result2.id,
|
|
6225
|
+
error: result2.error
|
|
4508
6226
|
} : {
|
|
4509
6227
|
kind: "tool-output",
|
|
4510
|
-
id:
|
|
4511
|
-
output:
|
|
6228
|
+
id: result2.id,
|
|
6229
|
+
output: result2.output
|
|
4512
6230
|
};
|
|
4513
6231
|
}
|
|
4514
6232
|
__name(outputFrame, "outputFrame");
|
|
4515
|
-
function refusalReason(
|
|
4516
|
-
const { output } =
|
|
6233
|
+
function refusalReason(result2) {
|
|
6234
|
+
const { output } = result2;
|
|
4517
6235
|
if (output !== null && typeof output === "object" && "reason" in output) {
|
|
4518
6236
|
const reason = output.reason;
|
|
4519
6237
|
return typeof reason === "string" && reason !== DEFAULT_REFUSAL_REASON ? reason : void 0;
|
|
@@ -4544,14 +6262,16 @@ async function invokeClaimedToolsTogether(turn, parallel, claimed) {
|
|
|
4544
6262
|
return results;
|
|
4545
6263
|
}
|
|
4546
6264
|
__name(invokeClaimedToolsTogether, "invokeClaimedToolsTogether");
|
|
4547
|
-
async function runAgentLoop(boundDeps,
|
|
6265
|
+
async function runAgentLoop(boundDeps, requested, hooks) {
|
|
6266
|
+
const persona = requested.persona === void 0 ? void 0 : await hooks.step("persona:resolve", () => resolveTurnPersona(boundDeps, requested)) ?? void 0;
|
|
6267
|
+
const input = persona === void 0 || persona.id !== requested.persona ? withoutPersona(requested) : requested;
|
|
4548
6268
|
const deps = input.model === void 0 ? boundDeps : {
|
|
4549
6269
|
...boundDeps,
|
|
4550
6270
|
model: withSelectedModel(boundDeps.model, input.model),
|
|
4551
6271
|
modelId: input.model
|
|
4552
6272
|
};
|
|
4553
6273
|
const maxSteps = deps.maxSteps ?? 8;
|
|
4554
|
-
let system = await resolveSystemPrompt(deps, input);
|
|
6274
|
+
let system = await resolveSystemPrompt(deps, input, persona);
|
|
4555
6275
|
const inputProcessors = deps.inputProcessors ?? [];
|
|
4556
6276
|
const outputProcessors = deps.outputProcessors ?? [];
|
|
4557
6277
|
const gateMode = resolveOutputGateMode(outputProcessors);
|
|
@@ -4592,6 +6312,9 @@ async function runAgentLoop(boundDeps, input, hooks) {
|
|
|
4592
6312
|
role: "user",
|
|
4593
6313
|
content: input.userText,
|
|
4594
6314
|
runId: hooks.runId,
|
|
6315
|
+
...input.persona !== void 0 ? {
|
|
6316
|
+
persona: input.persona
|
|
6317
|
+
} : {},
|
|
4595
6318
|
...input.attachments !== void 0 ? {
|
|
4596
6319
|
attachments: input.attachments
|
|
4597
6320
|
} : {}
|
|
@@ -4614,6 +6337,9 @@ async function runAgentLoop(boundDeps, input, hooks) {
|
|
|
4614
6337
|
actorId: input.actor.id,
|
|
4615
6338
|
...input.agentName !== void 0 ? {
|
|
4616
6339
|
agentName: input.agentName
|
|
6340
|
+
} : {},
|
|
6341
|
+
...input.persona !== void 0 ? {
|
|
6342
|
+
persona: input.persona
|
|
4617
6343
|
} : {}
|
|
4618
6344
|
});
|
|
4619
6345
|
const stages = await resolvePromptStages(deps, hooks);
|
|
@@ -4745,19 +6471,44 @@ ${block}`;
|
|
|
4745
6471
|
messages: prompt.messages,
|
|
4746
6472
|
actor: input.actor,
|
|
4747
6473
|
threadId: input.threadId,
|
|
6474
|
+
actionApprovalMode: history.actionApprovalMode ?? "blocking",
|
|
6475
|
+
preflightContext: {
|
|
6476
|
+
actor: input.actor,
|
|
6477
|
+
threadId: input.threadId,
|
|
6478
|
+
runId: hooks.runId,
|
|
6479
|
+
requestId: hooks.runId,
|
|
6480
|
+
...input.agentName !== void 0 ? {
|
|
6481
|
+
agentName: input.agentName
|
|
6482
|
+
} : {},
|
|
6483
|
+
...input.persona !== void 0 ? {
|
|
6484
|
+
persona: input.persona
|
|
6485
|
+
} : {},
|
|
6486
|
+
...input.pageContext !== void 0 ? {
|
|
6487
|
+
pageContext: input.pageContext
|
|
6488
|
+
} : {},
|
|
6489
|
+
...input.uiCapabilities !== void 0 ? {
|
|
6490
|
+
uiCapabilities: input.uiCapabilities
|
|
6491
|
+
} : {}
|
|
6492
|
+
},
|
|
4748
6493
|
...gated ? {
|
|
4749
6494
|
bufferOutput: true
|
|
4750
6495
|
} : {},
|
|
4751
6496
|
...input.model !== void 0 ? {
|
|
4752
6497
|
model: input.model
|
|
6498
|
+
} : {},
|
|
6499
|
+
...persona?.allowedTools !== void 0 ? {
|
|
6500
|
+
personaAllowedTools: persona.allowedTools
|
|
4753
6501
|
} : {}
|
|
4754
6502
|
});
|
|
4755
6503
|
} else {
|
|
4756
6504
|
const tools = withMemoryTool({
|
|
4757
6505
|
tools: withSkillTool({
|
|
4758
6506
|
tools: withAskTool({
|
|
4759
|
-
tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList, {
|
|
6507
|
+
tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, intersectAllowLists(deps.toolAllowList, persona?.allowedTools), {
|
|
4760
6508
|
threadId: input.threadId,
|
|
6509
|
+
...input.uiCapabilities !== void 0 ? {
|
|
6510
|
+
uiCapabilities: input.uiCapabilities
|
|
6511
|
+
} : {},
|
|
4761
6512
|
...input.agentName !== void 0 ? {
|
|
4762
6513
|
agentName: input.agentName
|
|
4763
6514
|
} : {}
|
|
@@ -4777,7 +6528,7 @@ ${block}`;
|
|
|
4777
6528
|
}) : void 0;
|
|
4778
6529
|
const buffer = gateMode === "whole" ? createFrameBuffer() : void 0;
|
|
4779
6530
|
const frames = observeTurnFrames(incremental?.writer ?? buffer?.writer ?? writer);
|
|
4780
|
-
const
|
|
6531
|
+
const result2 = stampToolKinds(withTurnFrames(await traceLlmTurn(hooks.runId, i, () => deps.model.runTurn({
|
|
4781
6532
|
system: prompt.system,
|
|
4782
6533
|
messages: prompt.messages,
|
|
4783
6534
|
tools,
|
|
@@ -4787,15 +6538,15 @@ ${block}`;
|
|
|
4787
6538
|
await incremental.settled();
|
|
4788
6539
|
const refusal = incremental.rejection();
|
|
4789
6540
|
return {
|
|
4790
|
-
...
|
|
6541
|
+
...result2,
|
|
4791
6542
|
releasedText: incremental.released(),
|
|
4792
6543
|
...refusal !== void 0 ? {
|
|
4793
6544
|
gateRejection: refusal
|
|
4794
6545
|
} : {}
|
|
4795
6546
|
};
|
|
4796
6547
|
}
|
|
4797
|
-
return buffer === void 0 ?
|
|
4798
|
-
...
|
|
6548
|
+
return buffer === void 0 ? result2 : {
|
|
6549
|
+
...result2,
|
|
4799
6550
|
bufferedFrames: buffer.frames()
|
|
4800
6551
|
};
|
|
4801
6552
|
});
|
|
@@ -4889,12 +6640,12 @@ ${block}`;
|
|
|
4889
6640
|
role: "assistant",
|
|
4890
6641
|
content: turn.text
|
|
4891
6642
|
}
|
|
4892
|
-
], count), (
|
|
4893
|
-
followUps:
|
|
4894
|
-
inputTokens:
|
|
4895
|
-
outputTokens:
|
|
4896
|
-
...
|
|
4897
|
-
modelId:
|
|
6643
|
+
], count), (result2) => ({
|
|
6644
|
+
followUps: result2.followUps.length,
|
|
6645
|
+
inputTokens: result2.usage.inputTokens,
|
|
6646
|
+
outputTokens: result2.usage.outputTokens,
|
|
6647
|
+
...result2.modelId !== void 0 ? {
|
|
6648
|
+
modelId: result2.modelId
|
|
4898
6649
|
} : {}
|
|
4899
6650
|
})));
|
|
4900
6651
|
let suggestions = generated.followUps;
|
|
@@ -4971,6 +6722,9 @@ ${block}`;
|
|
|
4971
6722
|
...input.agentName !== void 0 ? {
|
|
4972
6723
|
agentName: input.agentName
|
|
4973
6724
|
} : {},
|
|
6725
|
+
...input.persona !== void 0 ? {
|
|
6726
|
+
persona: input.persona
|
|
6727
|
+
} : {},
|
|
4974
6728
|
...turn.reasoning !== void 0 ? {
|
|
4975
6729
|
reasoning: turn.reasoning
|
|
4976
6730
|
} : {},
|
|
@@ -5002,7 +6756,7 @@ ${block}`;
|
|
|
5002
6756
|
};
|
|
5003
6757
|
modelMessages.push(assistantMessage);
|
|
5004
6758
|
for (const entry of synthetic) {
|
|
5005
|
-
const { call, result } = entry;
|
|
6759
|
+
const { call, result: result2 } = entry;
|
|
5006
6760
|
await hooks.step(`${entry.step}:${assistant.id}`, async () => {
|
|
5007
6761
|
await deps.store.recordToolCall({
|
|
5008
6762
|
toolCallId: call.id,
|
|
@@ -5016,7 +6770,7 @@ ${block}`;
|
|
|
5016
6770
|
await deps.store.updateToolCall({
|
|
5017
6771
|
toolCallId: call.id,
|
|
5018
6772
|
status: "executed",
|
|
5019
|
-
output:
|
|
6773
|
+
output: result2.output
|
|
5020
6774
|
});
|
|
5021
6775
|
await writer.write(encodeStreamEvent({
|
|
5022
6776
|
kind: "tool-input-available",
|
|
@@ -5028,7 +6782,7 @@ ${block}`;
|
|
|
5028
6782
|
await writer.write(encodeStreamEvent({
|
|
5029
6783
|
kind: "tool-output",
|
|
5030
6784
|
id: call.id,
|
|
5031
|
-
output:
|
|
6785
|
+
output: result2.output
|
|
5032
6786
|
}));
|
|
5033
6787
|
});
|
|
5034
6788
|
}
|
|
@@ -5057,14 +6811,19 @@ ${block}`;
|
|
|
5057
6811
|
messageId: assistant.id,
|
|
5058
6812
|
writer,
|
|
5059
6813
|
toolUi: /* @__PURE__ */ new Map(),
|
|
6814
|
+
toolText: /* @__PURE__ */ new Map(),
|
|
5060
6815
|
halt: {
|
|
5061
6816
|
terminal: false
|
|
5062
6817
|
},
|
|
6818
|
+
actionApprovalMode: history.actionApprovalMode ?? "blocking",
|
|
5063
6819
|
...skillOffer !== void 0 ? {
|
|
5064
6820
|
skills: skillOffer
|
|
5065
6821
|
} : {},
|
|
5066
6822
|
...memoryDigest !== void 0 ? {
|
|
5067
6823
|
memory: memoryDigest
|
|
6824
|
+
} : {},
|
|
6825
|
+
...persona !== void 0 ? {
|
|
6826
|
+
persona
|
|
5068
6827
|
} : {}
|
|
5069
6828
|
};
|
|
5070
6829
|
const parallel = hooks.parallel;
|
|
@@ -5089,17 +6848,35 @@ ${block}`;
|
|
|
5089
6848
|
...results,
|
|
5090
6849
|
...syntheticResults
|
|
5091
6850
|
];
|
|
6851
|
+
const toolText = escapeUnsafeToolUiText(toolCallsWithKind.map((call) => turnCalls.toolText.get(call.id)).filter((text) => text !== void 0).join("\n"));
|
|
5092
6852
|
assistantMessage.toolResults = settledResults;
|
|
5093
6853
|
await hooks.step(`stream:tool-outputs:${i}`, async () => {
|
|
5094
6854
|
await deps.store.setMessageToolResults(assistant.id, settledResults);
|
|
6855
|
+
if (toolText) await deps.store.appendMessage({
|
|
6856
|
+
threadId: input.threadId,
|
|
6857
|
+
role: "assistant",
|
|
6858
|
+
content: toolText,
|
|
6859
|
+
runId: hooks.runId,
|
|
6860
|
+
...input.agentName !== void 0 ? {
|
|
6861
|
+
agentName: input.agentName
|
|
6862
|
+
} : {}
|
|
6863
|
+
});
|
|
5095
6864
|
const toolUi = toolCallsWithKind.flatMap((call) => turnCalls.toolUi.get(call.id) ?? []);
|
|
5096
6865
|
if (toolUi.length > 0) {
|
|
5097
6866
|
await deps.store.setMessageUi?.(assistant.id, mergeUi(turn.ui, toolUi));
|
|
5098
6867
|
}
|
|
5099
|
-
for (const
|
|
5100
|
-
await writer.write(encodeStreamEvent(outputFrame(
|
|
6868
|
+
for (const result2 of results) {
|
|
6869
|
+
await writer.write(encodeStreamEvent(outputFrame(result2)));
|
|
5101
6870
|
}
|
|
5102
6871
|
});
|
|
6872
|
+
if (toolText) {
|
|
6873
|
+
modelMessages.push({
|
|
6874
|
+
role: "assistant",
|
|
6875
|
+
content: toolText
|
|
6876
|
+
});
|
|
6877
|
+
lastText += `
|
|
6878
|
+
${toolText}`;
|
|
6879
|
+
}
|
|
5103
6880
|
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
5104
6881
|
await writer.write(encodeStreamEvent({
|
|
5105
6882
|
kind: "step-finish",
|
|
@@ -5113,7 +6890,7 @@ ${block}`;
|
|
|
5113
6890
|
} : {}
|
|
5114
6891
|
}));
|
|
5115
6892
|
});
|
|
5116
|
-
if (turnCalls.halt.terminal) {
|
|
6893
|
+
if (turnCalls.halt.terminal || turnCalls.halt.independentProposal) {
|
|
5117
6894
|
break;
|
|
5118
6895
|
}
|
|
5119
6896
|
}
|
|
@@ -5169,8 +6946,152 @@ ${block}`;
|
|
|
5169
6946
|
}
|
|
5170
6947
|
__name(runAgentLoop, "runAgentLoop");
|
|
5171
6948
|
|
|
6949
|
+
// src/in-memory-action-proposal-store.ts
|
|
6950
|
+
var import_node_crypto2 = require("crypto");
|
|
6951
|
+
var InMemoryActionProposalStore = class {
|
|
6952
|
+
static {
|
|
6953
|
+
__name(this, "InMemoryActionProposalStore");
|
|
6954
|
+
}
|
|
6955
|
+
rows = /* @__PURE__ */ new Map();
|
|
6956
|
+
clock;
|
|
6957
|
+
constructor(options = {}) {
|
|
6958
|
+
this.clock = options.clock ?? Date.now;
|
|
6959
|
+
}
|
|
6960
|
+
async createActionProposal(input) {
|
|
6961
|
+
validateActionProposalCreation(input);
|
|
6962
|
+
const row = this.rows.get(input.id);
|
|
6963
|
+
if (row) {
|
|
6964
|
+
if (!actionProposalScopeMatches(row, input)) return {
|
|
6965
|
+
status: "conflict"
|
|
6966
|
+
};
|
|
6967
|
+
return {
|
|
6968
|
+
status: actionProposalCreationMatches(row, input) ? "unchanged" : "conflict",
|
|
6969
|
+
proposal: snapshotActionProposal(row)
|
|
6970
|
+
};
|
|
6971
|
+
}
|
|
6972
|
+
const proposal = initialActionProposal(input, this.clock());
|
|
6973
|
+
this.rows.set(input.id, proposal);
|
|
6974
|
+
return {
|
|
6975
|
+
status: "created",
|
|
6976
|
+
proposal: snapshotActionProposal(proposal)
|
|
6977
|
+
};
|
|
6978
|
+
}
|
|
6979
|
+
async getActionProposal(scope, id) {
|
|
6980
|
+
const row = this.rows.get(id);
|
|
6981
|
+
return row && actionProposalScopeMatches(row, scope) ? snapshotActionProposal(row) : null;
|
|
6982
|
+
}
|
|
6983
|
+
async listActionProposals(scope, query = {}) {
|
|
6984
|
+
const limit = validateActionProposalListQuery(query);
|
|
6985
|
+
return [
|
|
6986
|
+
...this.rows.values()
|
|
6987
|
+
].filter((row) => actionProposalScopeMatches(row, scope) && (query.decision === void 0 || row.decision === query.decision) && (query.after === void 0 || row.createdAt > query.after.createdAt || row.createdAt === query.after.createdAt && row.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);
|
|
6988
|
+
}
|
|
6989
|
+
mutate(scope, id, transition) {
|
|
6990
|
+
const row = this.rows.get(id);
|
|
6991
|
+
if (!row || !actionProposalScopeMatches(row, scope)) return {
|
|
6992
|
+
status: "not_found"
|
|
6993
|
+
};
|
|
6994
|
+
const result2 = transition(row, this.clock());
|
|
6995
|
+
if (result2.proposal) this.rows.set(id, snapshotActionProposal(result2.proposal));
|
|
6996
|
+
return result2;
|
|
6997
|
+
}
|
|
6998
|
+
async decideActionProposal(scope, id, command) {
|
|
6999
|
+
return this.mutate(scope, id, (row, now) => transitionActionProposalDecision(row, command, now));
|
|
7000
|
+
}
|
|
7001
|
+
async claimActionProposal(scope, id, command) {
|
|
7002
|
+
return this.mutate(scope, id, (row, now) => transitionActionProposalClaim(row, command, now, (0, import_node_crypto2.randomUUID)()));
|
|
7003
|
+
}
|
|
7004
|
+
async extendActionProposalLease(scope, id, command) {
|
|
7005
|
+
return this.mutate(scope, id, (row, now) => transitionActionProposalLease(row, command, now));
|
|
7006
|
+
}
|
|
7007
|
+
async settleActionProposal(scope, id, command) {
|
|
7008
|
+
return this.mutate(scope, id, (row, now) => transitionActionProposalSettlement(row, command, now));
|
|
7009
|
+
}
|
|
7010
|
+
async claimNextActionProposal(command) {
|
|
7011
|
+
const now = this.clock();
|
|
7012
|
+
validateActionProposalWorkerClaim(command, now);
|
|
7013
|
+
const candidates = [
|
|
7014
|
+
...this.rows.values()
|
|
7015
|
+
].filter((row) => row.decision === "approved" && (row.execution?.status === "queued" || row.execution?.status === "executing" && row.execution.lease !== null && now >= row.execution.lease.expiresAt)).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, 32);
|
|
7016
|
+
for (const candidate of candidates) {
|
|
7017
|
+
const claimed = await this.claimActionProposal(candidate, candidate.id, command);
|
|
7018
|
+
if (claimed.status === "applied" && claimed.proposal) return claimed.proposal;
|
|
7019
|
+
}
|
|
7020
|
+
return null;
|
|
7021
|
+
}
|
|
7022
|
+
async expireActionProposals(command) {
|
|
7023
|
+
const now = this.clock();
|
|
7024
|
+
validateActionProposalExpiryBatch(command, now);
|
|
7025
|
+
const candidates = [
|
|
7026
|
+
...this.rows.values()
|
|
7027
|
+
].filter((row) => row.decision === "pending" && row.expiresAt !== null && now >= row.expiresAt).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, command.limit);
|
|
7028
|
+
let expired = 0;
|
|
7029
|
+
for (const candidate of candidates) {
|
|
7030
|
+
const result2 = await this.decideActionProposal(candidate, candidate.id, {
|
|
7031
|
+
decision: "expired",
|
|
7032
|
+
actorRef: "system",
|
|
7033
|
+
via: "expiry"
|
|
7034
|
+
});
|
|
7035
|
+
if (result2.status === "applied") expired++;
|
|
7036
|
+
}
|
|
7037
|
+
return expired;
|
|
7038
|
+
}
|
|
7039
|
+
async claimNextActionProposalOutcome(command) {
|
|
7040
|
+
const now = this.clock();
|
|
7041
|
+
validateActionProposalWorkerClaim(command, now);
|
|
7042
|
+
const candidates = [
|
|
7043
|
+
...this.rows.values()
|
|
7044
|
+
].filter((row) => row.outcomeDelivery?.status === "pending" && (!row.outcomeDelivery.lease || now >= row.outcomeDelivery.lease.expiresAt)).sort((a, b) => a.createdAt - b.createdAt || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, 32);
|
|
7045
|
+
for (const candidate of candidates) {
|
|
7046
|
+
const row = this.rows.get(candidate.id);
|
|
7047
|
+
if (!row) continue;
|
|
7048
|
+
const next = claimActionProposalOutcome(row, command, this.clock(), (0, import_node_crypto2.randomUUID)());
|
|
7049
|
+
if (!next?.outcome || !next.outcomeDelivery?.lease) continue;
|
|
7050
|
+
this.rows.set(next.id, next);
|
|
7051
|
+
return {
|
|
7052
|
+
outcome: snapshotActionProposal(next.outcome),
|
|
7053
|
+
lease: {
|
|
7054
|
+
outcomeId: next.outcome.id,
|
|
7055
|
+
token: next.outcomeDelivery.lease.token,
|
|
7056
|
+
generation: next.outcomeDelivery.generation
|
|
7057
|
+
}
|
|
7058
|
+
};
|
|
7059
|
+
}
|
|
7060
|
+
return null;
|
|
7061
|
+
}
|
|
7062
|
+
async createReplacingActionProposal(input) {
|
|
7063
|
+
validateActionProposalCreation(input);
|
|
7064
|
+
const existing = this.rows.get(input.id);
|
|
7065
|
+
if (existing) return this.createActionProposal(input);
|
|
7066
|
+
const proposal = initialActionProposal(input, this.clock());
|
|
7067
|
+
const replacements = [];
|
|
7068
|
+
if (input.replacementKey) for (const row of this.rows.values()) {
|
|
7069
|
+
if (row.decision !== "pending" || !actionProposalScopeMatches(row, input) || row.toolName !== input.toolName || row.replacementKey !== input.replacementKey) continue;
|
|
7070
|
+
const result2 = transitionActionProposalSupersession(row, proposal, {
|
|
7071
|
+
replacementProposalId: proposal.id,
|
|
7072
|
+
actorRef: input.actorRef,
|
|
7073
|
+
via: "supersession"
|
|
7074
|
+
}, this.clock());
|
|
7075
|
+
if (result2.proposal) replacements.push(result2.proposal);
|
|
7076
|
+
}
|
|
7077
|
+
this.rows.set(proposal.id, proposal);
|
|
7078
|
+
for (const row of replacements) this.rows.set(row.id, row);
|
|
7079
|
+
return {
|
|
7080
|
+
status: "created",
|
|
7081
|
+
proposal: snapshotActionProposal(proposal)
|
|
7082
|
+
};
|
|
7083
|
+
}
|
|
7084
|
+
async supersedeActionProposal(scope, id, command) {
|
|
7085
|
+
const replacement = this.rows.get(command.replacementProposalId);
|
|
7086
|
+
if (!replacement || !actionProposalScopeMatches(replacement, scope)) return {
|
|
7087
|
+
status: "not_found"
|
|
7088
|
+
};
|
|
7089
|
+
return this.mutate(scope, id, (row, now) => transitionActionProposalSupersession(row, replacement, command, now));
|
|
7090
|
+
}
|
|
7091
|
+
};
|
|
7092
|
+
|
|
5172
7093
|
// src/in-memory-store.ts
|
|
5173
|
-
var InMemoryAgentStore = class {
|
|
7094
|
+
var InMemoryAgentStore = class extends InMemoryActionProposalStore {
|
|
5174
7095
|
static {
|
|
5175
7096
|
__name(this, "InMemoryAgentStore");
|
|
5176
7097
|
}
|
|
@@ -5193,11 +7114,15 @@ var InMemoryAgentStore = class {
|
|
|
5193
7114
|
const row = {
|
|
5194
7115
|
id,
|
|
5195
7116
|
actorRef: input.actor.id,
|
|
7117
|
+
tenantRef: input.actor.tenantRef ?? null,
|
|
5196
7118
|
title: input.title ?? "New chat",
|
|
5197
7119
|
transient: input.transient ?? false,
|
|
5198
7120
|
createdAt: ts,
|
|
5199
7121
|
updatedAt: ts,
|
|
5200
|
-
messages: []
|
|
7122
|
+
messages: [],
|
|
7123
|
+
...input.persona !== void 0 ? {
|
|
7124
|
+
persona: input.persona
|
|
7125
|
+
} : {}
|
|
5201
7126
|
};
|
|
5202
7127
|
this.threads.set(id, row);
|
|
5203
7128
|
return this.toSummary(row);
|
|
@@ -5225,8 +7150,12 @@ var InMemoryAgentStore = class {
|
|
|
5225
7150
|
}
|
|
5226
7151
|
const approval = toolCallApprovalFromRow({
|
|
5227
7152
|
toolCallId: call.toolCallId,
|
|
7153
|
+
...call.proposalId !== void 0 ? {
|
|
7154
|
+
proposalId: call.proposalId
|
|
7155
|
+
} : {},
|
|
5228
7156
|
status: call.status,
|
|
5229
7157
|
approver: call.approver,
|
|
7158
|
+
confirmation: call.confirmation,
|
|
5230
7159
|
expiresAt: call.expiresAt,
|
|
5231
7160
|
remember: call.remember,
|
|
5232
7161
|
executedByRef: call.executedByRef,
|
|
@@ -5249,6 +7178,10 @@ var InMemoryAgentStore = class {
|
|
|
5249
7178
|
names.add(call.toolName);
|
|
5250
7179
|
}
|
|
5251
7180
|
}
|
|
7181
|
+
const thread = this.threads.get(threadId);
|
|
7182
|
+
if (thread) {
|
|
7183
|
+
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);
|
|
7184
|
+
}
|
|
5252
7185
|
return [
|
|
5253
7186
|
...names
|
|
5254
7187
|
];
|
|
@@ -5289,6 +7222,7 @@ var InMemoryAgentStore = class {
|
|
|
5289
7222
|
const row = {
|
|
5290
7223
|
id,
|
|
5291
7224
|
actorRef: source.actorRef,
|
|
7225
|
+
tenantRef: source.tenantRef,
|
|
5292
7226
|
title: source.title,
|
|
5293
7227
|
transient: false,
|
|
5294
7228
|
createdAt: ts,
|
|
@@ -5302,6 +7236,9 @@ var InMemoryAgentStore = class {
|
|
|
5302
7236
|
} : {},
|
|
5303
7237
|
...source.model != null ? {
|
|
5304
7238
|
model: source.model
|
|
7239
|
+
} : {},
|
|
7240
|
+
...source.persona != null ? {
|
|
7241
|
+
persona: source.persona
|
|
5305
7242
|
} : {}
|
|
5306
7243
|
};
|
|
5307
7244
|
this.threads.set(id, row);
|
|
@@ -5353,6 +7290,9 @@ var InMemoryAgentStore = class {
|
|
|
5353
7290
|
if (patch.model !== void 0) {
|
|
5354
7291
|
row.model = patch.model;
|
|
5355
7292
|
}
|
|
7293
|
+
if (patch.persona !== void 0) {
|
|
7294
|
+
row.persona = patch.persona;
|
|
7295
|
+
}
|
|
5356
7296
|
row.updatedAt = this.now();
|
|
5357
7297
|
}
|
|
5358
7298
|
async activeRunForThread(threadId) {
|
|
@@ -5366,6 +7306,10 @@ var InMemoryAgentStore = class {
|
|
|
5366
7306
|
async defaultAgentForThread(threadId) {
|
|
5367
7307
|
return this.threads.get(threadId)?.defaultAgent ?? null;
|
|
5368
7308
|
}
|
|
7309
|
+
/** The thread's persona, projected like {@link defaultAgentForThread}. */
|
|
7310
|
+
async personaForThread(threadId) {
|
|
7311
|
+
return this.threads.get(threadId)?.persona ?? null;
|
|
7312
|
+
}
|
|
5369
7313
|
/** The thread's pinned model, projected like {@link defaultAgentForThread}. */
|
|
5370
7314
|
async modelForThread(threadId) {
|
|
5371
7315
|
return this.threads.get(threadId)?.model ?? null;
|
|
@@ -5470,12 +7414,18 @@ var InMemoryAgentStore = class {
|
|
|
5470
7414
|
...input.agentName !== void 0 ? {
|
|
5471
7415
|
agentName: input.agentName
|
|
5472
7416
|
} : {},
|
|
7417
|
+
...input.persona !== void 0 ? {
|
|
7418
|
+
persona: input.persona
|
|
7419
|
+
} : {},
|
|
5473
7420
|
...input.model !== void 0 ? {
|
|
5474
7421
|
model: input.model
|
|
5475
7422
|
} : {},
|
|
5476
7423
|
...input.pageContext !== void 0 ? {
|
|
5477
7424
|
pageContext: input.pageContext
|
|
5478
7425
|
} : {},
|
|
7426
|
+
...input.uiCapabilities !== void 0 ? {
|
|
7427
|
+
uiCapabilities: input.uiCapabilities
|
|
7428
|
+
} : {},
|
|
5479
7429
|
...input.interrupt === true ? {
|
|
5480
7430
|
interrupt: true
|
|
5481
7431
|
} : {},
|
|
@@ -5580,6 +7530,78 @@ var InMemoryAgentStore = class {
|
|
|
5580
7530
|
}
|
|
5581
7531
|
return void 0;
|
|
5582
7532
|
}
|
|
7533
|
+
async getThreadActionProposalScope(threadId) {
|
|
7534
|
+
const row = this.threads.get(threadId);
|
|
7535
|
+
return row ? {
|
|
7536
|
+
threadId,
|
|
7537
|
+
actorRef: row.actorRef,
|
|
7538
|
+
tenantRef: row.tenantRef
|
|
7539
|
+
} : null;
|
|
7540
|
+
}
|
|
7541
|
+
async admitActionProposalOutcome(command) {
|
|
7542
|
+
const row = [
|
|
7543
|
+
...this.rows.values()
|
|
7544
|
+
].find((row2) => row2.outcome?.id === command.outcomeId);
|
|
7545
|
+
if (!row?.outcome || !row.outcomeDelivery) return {
|
|
7546
|
+
status: "not_found"
|
|
7547
|
+
};
|
|
7548
|
+
if (row.outcomeDelivery.status === "admitted") return {
|
|
7549
|
+
status: "unchanged",
|
|
7550
|
+
...row.outcomeDelivery.messageId !== void 0 ? {
|
|
7551
|
+
messageId: row.outcomeDelivery.messageId
|
|
7552
|
+
} : {}
|
|
7553
|
+
};
|
|
7554
|
+
if (row.outcomeDelivery.status === "discarded") return {
|
|
7555
|
+
status: "discarded"
|
|
7556
|
+
};
|
|
7557
|
+
if (!actionProposalOutcomeFenceValid(row, command, this.clock())) return {
|
|
7558
|
+
status: "conflict"
|
|
7559
|
+
};
|
|
7560
|
+
const thread = this.threads.get(row.threadId);
|
|
7561
|
+
if (!thread) {
|
|
7562
|
+
this.rows.set(row.id, snapshotActionProposal({
|
|
7563
|
+
...row,
|
|
7564
|
+
outcomeDelivery: {
|
|
7565
|
+
...row.outcomeDelivery,
|
|
7566
|
+
status: "discarded",
|
|
7567
|
+
lease: null
|
|
7568
|
+
}
|
|
7569
|
+
}));
|
|
7570
|
+
return {
|
|
7571
|
+
status: "discarded"
|
|
7572
|
+
};
|
|
7573
|
+
}
|
|
7574
|
+
if (thread.actorRef !== row.actorRef || thread.tenantRef !== row.tenantRef) return {
|
|
7575
|
+
status: "conflict"
|
|
7576
|
+
};
|
|
7577
|
+
if (thread.activeStreamId) return {
|
|
7578
|
+
status: "busy"
|
|
7579
|
+
};
|
|
7580
|
+
const message = {
|
|
7581
|
+
id: crypto.randomUUID(),
|
|
7582
|
+
role: "assistant",
|
|
7583
|
+
content: actionProposalOutcomeText(row.outcome),
|
|
7584
|
+
createdAt: this.now(),
|
|
7585
|
+
actionProposalOutcome: snapshotActionProposal(row.outcome),
|
|
7586
|
+
ui: snapshotActionProposal(row.outcome.ui)
|
|
7587
|
+
};
|
|
7588
|
+
const next = snapshotActionProposal({
|
|
7589
|
+
...row,
|
|
7590
|
+
outcomeDelivery: {
|
|
7591
|
+
...row.outcomeDelivery,
|
|
7592
|
+
status: "admitted",
|
|
7593
|
+
lease: null,
|
|
7594
|
+
messageId: message.id
|
|
7595
|
+
}
|
|
7596
|
+
});
|
|
7597
|
+
thread.messages.push(message);
|
|
7598
|
+
thread.updatedAt = message.createdAt;
|
|
7599
|
+
this.rows.set(row.id, next);
|
|
7600
|
+
return {
|
|
7601
|
+
status: "applied",
|
|
7602
|
+
messageId: message.id
|
|
7603
|
+
};
|
|
7604
|
+
}
|
|
5583
7605
|
async appendMessage(input) {
|
|
5584
7606
|
const row = this.threads.get(input.threadId);
|
|
5585
7607
|
if (row === void 0) {
|
|
@@ -5608,6 +7630,9 @@ var InMemoryAgentStore = class {
|
|
|
5608
7630
|
...input.agentName !== void 0 ? {
|
|
5609
7631
|
agentName: input.agentName
|
|
5610
7632
|
} : {},
|
|
7633
|
+
...input.persona !== void 0 ? {
|
|
7634
|
+
persona: input.persona
|
|
7635
|
+
} : {},
|
|
5611
7636
|
...input.runId !== void 0 ? {
|
|
5612
7637
|
runId: input.runId
|
|
5613
7638
|
} : {},
|
|
@@ -5619,6 +7644,9 @@ var InMemoryAgentStore = class {
|
|
|
5619
7644
|
} : {},
|
|
5620
7645
|
...input.ui !== void 0 ? {
|
|
5621
7646
|
ui: input.ui
|
|
7647
|
+
} : {},
|
|
7648
|
+
...input.actionProposalOutcome !== void 0 ? {
|
|
7649
|
+
actionProposalOutcome: input.actionProposalOutcome
|
|
5622
7650
|
} : {}
|
|
5623
7651
|
};
|
|
5624
7652
|
row.messages.push(message);
|
|
@@ -5710,6 +7738,9 @@ var InMemoryAgentStore = class {
|
|
|
5710
7738
|
async recordToolCall(input) {
|
|
5711
7739
|
this.toolCalls.set(input.toolCallId, {
|
|
5712
7740
|
toolCallId: input.toolCallId,
|
|
7741
|
+
...input.proposalId !== void 0 ? {
|
|
7742
|
+
proposalId: input.proposalId
|
|
7743
|
+
} : {},
|
|
5713
7744
|
messageId: input.messageId,
|
|
5714
7745
|
threadId: this.threadIdForMessage(input.messageId) ?? "",
|
|
5715
7746
|
toolName: input.toolName,
|
|
@@ -5723,6 +7754,9 @@ var InMemoryAgentStore = class {
|
|
|
5723
7754
|
...input.approver !== void 0 ? {
|
|
5724
7755
|
approver: input.approver
|
|
5725
7756
|
} : {},
|
|
7757
|
+
...input.confirmation !== void 0 ? {
|
|
7758
|
+
confirmation: structuredClone(input.confirmation)
|
|
7759
|
+
} : {},
|
|
5726
7760
|
...input.expiresAt !== void 0 ? {
|
|
5727
7761
|
expiresAt: input.expiresAt
|
|
5728
7762
|
} : {}
|
|
@@ -6024,13 +8058,14 @@ var InMemoryAgentStore = class {
|
|
|
6024
8058
|
defaultAgent: row.defaultAgent ?? null,
|
|
6025
8059
|
...row.model != null ? {
|
|
6026
8060
|
model: row.model
|
|
6027
|
-
} : {}
|
|
8061
|
+
} : {},
|
|
8062
|
+
persona: row.persona ?? null
|
|
6028
8063
|
};
|
|
6029
8064
|
}
|
|
6030
8065
|
};
|
|
6031
8066
|
|
|
6032
8067
|
// src/confirm-token.ts
|
|
6033
|
-
var
|
|
8068
|
+
var import_node_crypto3 = require("crypto");
|
|
6034
8069
|
var DEFAULT_CONFIRM_TTL_MS = 15 * 60 * 1e3;
|
|
6035
8070
|
function canonicalJson(value) {
|
|
6036
8071
|
if (value === void 0) return "null";
|
|
@@ -6047,7 +8082,7 @@ function signature(subject, expiresAt, secret) {
|
|
|
6047
8082
|
if (secret === "") {
|
|
6048
8083
|
throw new Error("confirm token: the secret is empty");
|
|
6049
8084
|
}
|
|
6050
|
-
return (0,
|
|
8085
|
+
return (0, import_node_crypto3.createHmac)("sha256", secret).update(canonicalJson([
|
|
6051
8086
|
"agent-confirm",
|
|
6052
8087
|
subject.tool,
|
|
6053
8088
|
subject.actorId,
|
|
@@ -6074,11 +8109,11 @@ function verifyConfirmToken(token, subject, options) {
|
|
|
6074
8109
|
if (expiresAt === void 0 || expiresAt < (options.now ?? Date.now())) return false;
|
|
6075
8110
|
const expected = Buffer.from(signature(subject, expiresAt, options.secret));
|
|
6076
8111
|
const given = Buffer.from(token.slice(token.indexOf(".") + 1));
|
|
6077
|
-
return expected.length === given.length && (0,
|
|
8112
|
+
return expected.length === given.length && (0, import_node_crypto3.timingSafeEqual)(expected, given);
|
|
6078
8113
|
}
|
|
6079
8114
|
__name(verifyConfirmToken, "verifyConfirmToken");
|
|
6080
8115
|
function hashConfirmToken(token) {
|
|
6081
|
-
return (0,
|
|
8116
|
+
return (0, import_node_crypto3.createHash)("sha256").update(token).digest("hex");
|
|
6082
8117
|
}
|
|
6083
8118
|
__name(hashConfirmToken, "hashConfirmToken");
|
|
6084
8119
|
var InMemoryConfirmTokenStore = class {
|
|
@@ -6226,12 +8261,12 @@ function withConfirmFields(schema) {
|
|
|
6226
8261
|
});
|
|
6227
8262
|
}
|
|
6228
8263
|
const { args, fields } = splitConfirm(value);
|
|
6229
|
-
const
|
|
6230
|
-
if (
|
|
8264
|
+
const result2 = await inner.validate(args);
|
|
8265
|
+
if (result2.issues !== void 0) {
|
|
6231
8266
|
return {
|
|
6232
8267
|
issues: [
|
|
6233
8268
|
...issues,
|
|
6234
|
-
...
|
|
8269
|
+
...result2.issues
|
|
6235
8270
|
]
|
|
6236
8271
|
};
|
|
6237
8272
|
}
|
|
@@ -6241,10 +8276,10 @@ function withConfirmFields(schema) {
|
|
|
6241
8276
|
};
|
|
6242
8277
|
}
|
|
6243
8278
|
return {
|
|
6244
|
-
value: isRecord(
|
|
6245
|
-
...
|
|
8279
|
+
value: isRecord(result2.value) ? {
|
|
8280
|
+
...result2.value,
|
|
6246
8281
|
...fields
|
|
6247
|
-
} :
|
|
8282
|
+
} : result2.value
|
|
6248
8283
|
};
|
|
6249
8284
|
}, "validate"),
|
|
6250
8285
|
jsonSchema: {
|
|
@@ -6576,6 +8611,309 @@ var SqlTokenStreamSink = class {
|
|
|
6576
8611
|
});
|
|
6577
8612
|
}
|
|
6578
8613
|
};
|
|
8614
|
+
|
|
8615
|
+
// src/action-proposal-text.ts
|
|
8616
|
+
function resolveTextActionProposalDecision(text, proposals) {
|
|
8617
|
+
const command = parseTextActionProposalCommand(text);
|
|
8618
|
+
if (command.status === "unmatched") return command;
|
|
8619
|
+
const { decision, remember } = command;
|
|
8620
|
+
const pending = proposals.filter((proposal) => proposal.decision === "pending");
|
|
8621
|
+
const explicitId = command.proposalId;
|
|
8622
|
+
if (explicitId !== void 0) {
|
|
8623
|
+
if (!pending.some((proposal) => proposal.id === explicitId)) return {
|
|
8624
|
+
status: "unmatched"
|
|
8625
|
+
};
|
|
8626
|
+
return {
|
|
8627
|
+
status: "decision",
|
|
8628
|
+
proposalId: explicitId,
|
|
8629
|
+
decision,
|
|
8630
|
+
remember
|
|
8631
|
+
};
|
|
8632
|
+
}
|
|
8633
|
+
if (pending.length === 0) return {
|
|
8634
|
+
status: "unmatched"
|
|
8635
|
+
};
|
|
8636
|
+
if (pending.length > 1) return {
|
|
8637
|
+
status: "ambiguous",
|
|
8638
|
+
proposalIds: pending.map(({ id }) => id)
|
|
8639
|
+
};
|
|
8640
|
+
const candidate = pending[0];
|
|
8641
|
+
if (!candidate) return {
|
|
8642
|
+
status: "unmatched"
|
|
8643
|
+
};
|
|
8644
|
+
return {
|
|
8645
|
+
status: "decision",
|
|
8646
|
+
proposalId: candidate.id,
|
|
8647
|
+
decision,
|
|
8648
|
+
remember
|
|
8649
|
+
};
|
|
8650
|
+
}
|
|
8651
|
+
__name(resolveTextActionProposalDecision, "resolveTextActionProposalDecision");
|
|
8652
|
+
function parseTextActionProposalCommand(text) {
|
|
8653
|
+
if (/[\r\n]/u.test(text)) return {
|
|
8654
|
+
status: "unmatched"
|
|
8655
|
+
};
|
|
8656
|
+
const normalized = text.trim();
|
|
8657
|
+
const match = /^(sim|confirmo|confirmar|aprovar|aprovo|cancelar|rejeitar|rejeito|não|nao)(?: (sempre nesta conversa))?(?: #([^\s]+?))?[.!]?$/iu.exec(normalized);
|
|
8658
|
+
if (!match) return {
|
|
8659
|
+
status: "unmatched"
|
|
8660
|
+
};
|
|
8661
|
+
const verb = match[1]?.toLocaleLowerCase("pt-BR");
|
|
8662
|
+
if (verb === void 0) return {
|
|
8663
|
+
status: "unmatched"
|
|
8664
|
+
};
|
|
8665
|
+
const decision = [
|
|
8666
|
+
"cancelar",
|
|
8667
|
+
"rejeitar",
|
|
8668
|
+
"rejeito",
|
|
8669
|
+
"n\xE3o",
|
|
8670
|
+
"nao"
|
|
8671
|
+
].includes(verb) ? "rejected" : "approved";
|
|
8672
|
+
const remember = match[2] !== void 0;
|
|
8673
|
+
if (remember && decision !== "approved") return {
|
|
8674
|
+
status: "unmatched"
|
|
8675
|
+
};
|
|
8676
|
+
return {
|
|
8677
|
+
status: "command",
|
|
8678
|
+
decision,
|
|
8679
|
+
remember,
|
|
8680
|
+
...match[3] !== void 0 ? {
|
|
8681
|
+
proposalId: match[3]
|
|
8682
|
+
} : {}
|
|
8683
|
+
};
|
|
8684
|
+
}
|
|
8685
|
+
__name(parseTextActionProposalCommand, "parseTextActionProposalCommand");
|
|
8686
|
+
|
|
8687
|
+
// src/action-proposal-executor.ts
|
|
8688
|
+
var ActionProposalExecutor = class {
|
|
8689
|
+
static {
|
|
8690
|
+
__name(this, "ActionProposalExecutor");
|
|
8691
|
+
}
|
|
8692
|
+
options;
|
|
8693
|
+
constructor(options) {
|
|
8694
|
+
this.options = options;
|
|
8695
|
+
}
|
|
8696
|
+
async execute(proposal) {
|
|
8697
|
+
let ui = createNegotiatedUiCollector(proposal.originToolCallId, {
|
|
8698
|
+
actor: {
|
|
8699
|
+
id: proposal.actorRef
|
|
8700
|
+
},
|
|
8701
|
+
threadId: proposal.threadId
|
|
8702
|
+
});
|
|
8703
|
+
try {
|
|
8704
|
+
const actor = await this.options.resolver.resolve({
|
|
8705
|
+
actorRef: proposal.actorRef,
|
|
8706
|
+
tenantRef: proposal.tenantRef
|
|
8707
|
+
});
|
|
8708
|
+
if (!actor || actor.id !== proposal.actorRef || (actor.tenantRef ?? null) !== proposal.tenantRef) throw new Error("Action proposal requester no longer exists or scope changed");
|
|
8709
|
+
const deps = await this.options.resolveExecution(proposal, actor);
|
|
8710
|
+
if (deps.registry.spec(proposal.toolName)?.kind !== "action") throw new Error("Action proposal tool no longer exists as an action");
|
|
8711
|
+
const context = proposal.executionContext;
|
|
8712
|
+
ui = createNegotiatedUiCollector(proposal.originToolCallId, {
|
|
8713
|
+
actor,
|
|
8714
|
+
threadId: proposal.threadId,
|
|
8715
|
+
...context?.agentName !== void 0 ? {
|
|
8716
|
+
agentName: context.agentName
|
|
8717
|
+
} : {},
|
|
8718
|
+
...context?.uiCapabilities !== void 0 ? {
|
|
8719
|
+
uiCapabilities: context.uiCapabilities
|
|
8720
|
+
} : {}
|
|
8721
|
+
}, deps.resolveUiCatalog);
|
|
8722
|
+
const output = await deps.registry.invoke(proposal.toolName, snapshotActionProposal(Object.hasOwn(proposal, "preparationInput") ? proposal.preparationInput : proposal.input), {
|
|
8723
|
+
actor,
|
|
8724
|
+
threadId: proposal.threadId,
|
|
8725
|
+
runId: proposal.originRunId,
|
|
8726
|
+
requestId: context?.requestId ?? proposal.originRunId,
|
|
8727
|
+
toolCallId: proposal.originToolCallId,
|
|
8728
|
+
idempotencyKey: proposal.idempotencyKey,
|
|
8729
|
+
...context?.agentName !== void 0 ? {
|
|
8730
|
+
agentName: context.agentName
|
|
8731
|
+
} : {},
|
|
8732
|
+
...context?.persona !== void 0 ? {
|
|
8733
|
+
persona: context.persona
|
|
8734
|
+
} : {},
|
|
8735
|
+
...context?.pageContext !== void 0 ? {
|
|
8736
|
+
pageContext: context.pageContext
|
|
8737
|
+
} : {},
|
|
8738
|
+
...context?.uiCapabilities !== void 0 ? {
|
|
8739
|
+
uiCapabilities: context.uiCapabilities
|
|
8740
|
+
} : {},
|
|
8741
|
+
...deps.host !== void 0 ? {
|
|
8742
|
+
host: deps.host
|
|
8743
|
+
} : {},
|
|
8744
|
+
emitUi: ui.emit
|
|
8745
|
+
}, deps.rolesPolicy, {
|
|
8746
|
+
approvedInput: proposal.input,
|
|
8747
|
+
...deps.allowedTools !== void 0 ? {
|
|
8748
|
+
allowedTools: deps.allowedTools
|
|
8749
|
+
} : {}
|
|
8750
|
+
});
|
|
8751
|
+
return snapshotActionProposal({
|
|
8752
|
+
status: "succeeded",
|
|
8753
|
+
...output !== void 0 ? {
|
|
8754
|
+
result: output
|
|
8755
|
+
} : {},
|
|
8756
|
+
ui: ui.components(),
|
|
8757
|
+
...ui.text() ? {
|
|
8758
|
+
text: ui.text()
|
|
8759
|
+
} : {}
|
|
8760
|
+
});
|
|
8761
|
+
} catch (error) {
|
|
8762
|
+
return {
|
|
8763
|
+
status: "failed",
|
|
8764
|
+
error: error instanceof Error ? error.message : String(error),
|
|
8765
|
+
ui: ui.components(),
|
|
8766
|
+
...ui.text() ? {
|
|
8767
|
+
text: ui.text()
|
|
8768
|
+
} : {}
|
|
8769
|
+
};
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
};
|
|
8773
|
+
|
|
8774
|
+
// src/action-proposal-worker.ts
|
|
8775
|
+
var ActionProposalWorker = class {
|
|
8776
|
+
static {
|
|
8777
|
+
__name(this, "ActionProposalWorker");
|
|
8778
|
+
}
|
|
8779
|
+
options;
|
|
8780
|
+
leaseMs;
|
|
8781
|
+
pollIntervalMs;
|
|
8782
|
+
maxConcurrency;
|
|
8783
|
+
timer;
|
|
8784
|
+
stopped = false;
|
|
8785
|
+
renewals = /* @__PURE__ */ new Set();
|
|
8786
|
+
active;
|
|
8787
|
+
constructor(options) {
|
|
8788
|
+
this.options = options;
|
|
8789
|
+
this.leaseMs = options.leaseMs ?? 3e4;
|
|
8790
|
+
this.pollIntervalMs = options.pollIntervalMs ?? 1e3;
|
|
8791
|
+
this.maxConcurrency = options.maxConcurrency ?? 1;
|
|
8792
|
+
for (const value of [
|
|
8793
|
+
this.leaseMs,
|
|
8794
|
+
this.pollIntervalMs,
|
|
8795
|
+
this.maxConcurrency
|
|
8796
|
+
]) if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError("Worker configuration must be positive safe integers");
|
|
8797
|
+
if (this.pollIntervalMs >= this.leaseMs / 3) throw new RangeError("Worker poll interval must be below one third of lease");
|
|
8798
|
+
if (!options.workerId) throw new TypeError("workerId is required");
|
|
8799
|
+
}
|
|
8800
|
+
start() {
|
|
8801
|
+
if (this.timer !== void 0 || this.stopped) return;
|
|
8802
|
+
const tick = /* @__PURE__ */ __name(async () => {
|
|
8803
|
+
if (this.stopped) return;
|
|
8804
|
+
try {
|
|
8805
|
+
await this.runOnce();
|
|
8806
|
+
} catch (error) {
|
|
8807
|
+
this.options.onError?.(error);
|
|
8808
|
+
}
|
|
8809
|
+
if (!this.stopped) this.timer = setTimeout(tick, this.pollIntervalMs);
|
|
8810
|
+
}, "tick");
|
|
8811
|
+
this.timer = setTimeout(tick, 0);
|
|
8812
|
+
}
|
|
8813
|
+
async stop() {
|
|
8814
|
+
this.stopped = true;
|
|
8815
|
+
for (const timer of this.renewals) clearInterval(timer);
|
|
8816
|
+
this.renewals.clear();
|
|
8817
|
+
if (this.timer !== void 0) clearTimeout(this.timer);
|
|
8818
|
+
await this.active;
|
|
8819
|
+
}
|
|
8820
|
+
runOnce() {
|
|
8821
|
+
if (this.active) return this.active;
|
|
8822
|
+
if (this.stopped) return Promise.resolve();
|
|
8823
|
+
const task = this.tick();
|
|
8824
|
+
this.active = task;
|
|
8825
|
+
return task.finally(() => {
|
|
8826
|
+
if (this.active === task) this.active = void 0;
|
|
8827
|
+
});
|
|
8828
|
+
}
|
|
8829
|
+
async tick() {
|
|
8830
|
+
await this.options.store.expireActionProposals({
|
|
8831
|
+
limit: 100
|
|
8832
|
+
});
|
|
8833
|
+
const work = [];
|
|
8834
|
+
for (let index = 0; index < this.maxConcurrency && !this.stopped; index++) {
|
|
8835
|
+
const proposal = await this.options.store.claimNextActionProposal({
|
|
8836
|
+
workerId: this.options.workerId,
|
|
8837
|
+
leaseMs: this.leaseMs
|
|
8838
|
+
});
|
|
8839
|
+
if (!proposal) break;
|
|
8840
|
+
work.push(this.execute(proposal));
|
|
8841
|
+
}
|
|
8842
|
+
await Promise.all(work);
|
|
8843
|
+
for (let index = 0; index < 32 && !this.stopped; index++) {
|
|
8844
|
+
const delivery = await this.options.store.claimNextActionProposalOutcome({
|
|
8845
|
+
workerId: this.options.workerId,
|
|
8846
|
+
leaseMs: this.leaseMs
|
|
8847
|
+
});
|
|
8848
|
+
if (!delivery) break;
|
|
8849
|
+
await this.options.store.admitActionProposalOutcome(delivery.lease);
|
|
8850
|
+
}
|
|
8851
|
+
}
|
|
8852
|
+
async execute(proposal) {
|
|
8853
|
+
const lease = proposal.execution?.lease;
|
|
8854
|
+
if (!lease) throw new Error("Claimed action lacks execution lease");
|
|
8855
|
+
let fenced = true;
|
|
8856
|
+
let renewing;
|
|
8857
|
+
const renew = /* @__PURE__ */ __name(() => {
|
|
8858
|
+
if (renewing || !fenced) return;
|
|
8859
|
+
renewing = this.options.store.extendActionProposalLease(proposal, proposal.id, {
|
|
8860
|
+
token: lease.token,
|
|
8861
|
+
generation: lease.generation,
|
|
8862
|
+
leaseMs: this.leaseMs
|
|
8863
|
+
}).then((result2) => {
|
|
8864
|
+
if (result2.status !== "applied") fenced = false;
|
|
8865
|
+
}, (error) => {
|
|
8866
|
+
fenced = false;
|
|
8867
|
+
this.options.onError?.(error);
|
|
8868
|
+
}).finally(() => {
|
|
8869
|
+
renewing = void 0;
|
|
8870
|
+
});
|
|
8871
|
+
}, "renew");
|
|
8872
|
+
const timer = setInterval(renew, this.leaseMs / 3);
|
|
8873
|
+
this.renewals.add(timer);
|
|
8874
|
+
try {
|
|
8875
|
+
const result2 = await this.options.executor.execute(proposal);
|
|
8876
|
+
clearInterval(timer);
|
|
8877
|
+
await renewing;
|
|
8878
|
+
if (!fenced) return;
|
|
8879
|
+
const settled = await this.options.store.settleActionProposal(proposal, proposal.id, {
|
|
8880
|
+
...result2,
|
|
8881
|
+
token: lease.token,
|
|
8882
|
+
generation: lease.generation
|
|
8883
|
+
});
|
|
8884
|
+
if (settled.status === "applied" && settled.proposal) await this.options.onSettled?.(settled.proposal);
|
|
8885
|
+
} finally {
|
|
8886
|
+
clearInterval(timer);
|
|
8887
|
+
this.renewals.delete(timer);
|
|
8888
|
+
await renewing;
|
|
8889
|
+
}
|
|
8890
|
+
}
|
|
8891
|
+
};
|
|
8892
|
+
|
|
8893
|
+
// src/action-proposal-capabilities.ts
|
|
8894
|
+
function assertIndependentActionCapabilities(store, resolver) {
|
|
8895
|
+
const candidate = store;
|
|
8896
|
+
if (!resolver || typeof resolver.resolve !== "function") throw new Error("Independent action mode requires a BackgroundActorResolver");
|
|
8897
|
+
if (!isChatQueueStore(store) || candidate.actionProposalAdmissionSupported === false) throw new Error("Independent action mode requires transactional thread admission");
|
|
8898
|
+
const required = [
|
|
8899
|
+
"createActionProposal",
|
|
8900
|
+
"getActionProposal",
|
|
8901
|
+
"listActionProposals",
|
|
8902
|
+
"decideActionProposal",
|
|
8903
|
+
"claimActionProposal",
|
|
8904
|
+
"extendActionProposalLease",
|
|
8905
|
+
"settleActionProposal",
|
|
8906
|
+
"claimNextActionProposal",
|
|
8907
|
+
"expireActionProposals",
|
|
8908
|
+
"getThreadActionProposalScope",
|
|
8909
|
+
"claimNextActionProposalOutcome",
|
|
8910
|
+
"admitActionProposalOutcome",
|
|
8911
|
+
"createReplacingActionProposal",
|
|
8912
|
+
"supersedeActionProposal"
|
|
8913
|
+
];
|
|
8914
|
+
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");
|
|
8915
|
+
}
|
|
8916
|
+
__name(assertIndependentActionCapabilities, "assertIndependentActionCapabilities");
|
|
6579
8917
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6580
8918
|
0 && (module.exports = {
|
|
6581
8919
|
AGENT_ACTOR_DIRECTORY,
|
|
@@ -6610,6 +8948,8 @@ var SqlTokenStreamSink = class {
|
|
|
6610
8948
|
APPROVAL_EXPIRED_REASON,
|
|
6611
8949
|
ASK_TOOL_DESCRIPTION,
|
|
6612
8950
|
ASK_TOOL_NAME,
|
|
8951
|
+
ActionProposalExecutor,
|
|
8952
|
+
ActionProposalWorker,
|
|
6613
8953
|
AgentRegistry,
|
|
6614
8954
|
AgentStreamError,
|
|
6615
8955
|
CONFIRM_JSON_SCHEMA_PROPERTIES,
|
|
@@ -6630,6 +8970,7 @@ var SqlTokenStreamSink = class {
|
|
|
6630
8970
|
DefaultRolesPolicy,
|
|
6631
8971
|
ELICITATION_INPUT_TYPES,
|
|
6632
8972
|
GLOBAL_SCOPE,
|
|
8973
|
+
InMemoryActionProposalStore,
|
|
6633
8974
|
InMemoryAgentStore,
|
|
6634
8975
|
InMemoryConfirmTokenStore,
|
|
6635
8976
|
MAX_ASK_QUESTIONS,
|
|
@@ -6653,15 +8994,25 @@ var SqlTokenStreamSink = class {
|
|
|
6653
8994
|
THREAD_DETAIL_CONTENT_CHARS,
|
|
6654
8995
|
ToolDisabledError,
|
|
6655
8996
|
ToolForbiddenError,
|
|
8997
|
+
ToolInputDriftError,
|
|
6656
8998
|
ToolInputInvalidError,
|
|
6657
8999
|
ToolNotFoundError,
|
|
9000
|
+
ToolPreflightDeniedError,
|
|
6658
9001
|
ToolRegistry,
|
|
6659
9002
|
UNFINISHED_TOOL_CALL,
|
|
9003
|
+
actionProposalCreationMatches,
|
|
9004
|
+
actionProposalOutcomeFenceValid,
|
|
9005
|
+
actionProposalOutcomeScope,
|
|
9006
|
+
actionProposalOutcomeText,
|
|
9007
|
+
actionProposalReceipt,
|
|
9008
|
+
actionProposalScopeMatches,
|
|
6660
9009
|
actorScope,
|
|
6661
9010
|
agentDiagnosticKey,
|
|
6662
9011
|
agentFailureCode,
|
|
6663
9012
|
askInputSchema,
|
|
6664
9013
|
askToolDefinition,
|
|
9014
|
+
assertIndependentActionCapabilities,
|
|
9015
|
+
attachActionProposalOutcome,
|
|
6665
9016
|
bucketByActor,
|
|
6666
9017
|
bucketByModel,
|
|
6667
9018
|
bucketByThread,
|
|
@@ -6669,12 +9020,15 @@ var SqlTokenStreamSink = class {
|
|
|
6669
9020
|
buildMemoryBlock,
|
|
6670
9021
|
buildSkillsBlock,
|
|
6671
9022
|
canActorUseTool,
|
|
9023
|
+
canonicalActionProposalJson,
|
|
6672
9024
|
canonicalJson,
|
|
9025
|
+
claimActionProposalOutcome,
|
|
6673
9026
|
closeEmptyRoles,
|
|
6674
9027
|
compositeSkillProvider,
|
|
6675
9028
|
confirmTokenExpiry,
|
|
6676
9029
|
createFrameBuffer,
|
|
6677
9030
|
createIncrementalGate,
|
|
9031
|
+
createNegotiatedUiCollector,
|
|
6678
9032
|
createNoopEmitUi,
|
|
6679
9033
|
createUiCollector,
|
|
6680
9034
|
danglingToolCallIds,
|
|
@@ -6687,6 +9041,7 @@ var SqlTokenStreamSink = class {
|
|
|
6687
9041
|
detachedStarted,
|
|
6688
9042
|
detachedUnsettled,
|
|
6689
9043
|
encodeStreamEvent,
|
|
9044
|
+
escapeUnsafeToolUiText,
|
|
6690
9045
|
estimateCost,
|
|
6691
9046
|
estimateMessageTokens,
|
|
6692
9047
|
exhaustedWindow,
|
|
@@ -6697,9 +9052,12 @@ var SqlTokenStreamSink = class {
|
|
|
6697
9052
|
filterToolsByEnabled,
|
|
6698
9053
|
filterToolsByRole,
|
|
6699
9054
|
findCatalogModel,
|
|
9055
|
+
findPersona,
|
|
6700
9056
|
gateFollowUps,
|
|
6701
9057
|
gateTail,
|
|
6702
9058
|
hashConfirmToken,
|
|
9059
|
+
initialActionProposal,
|
|
9060
|
+
intersectAllowLists,
|
|
6703
9061
|
invokeWithTransientRetry,
|
|
6704
9062
|
isChatQueueStore,
|
|
6705
9063
|
isControlFlowSignal,
|
|
@@ -6717,6 +9075,9 @@ var SqlTokenStreamSink = class {
|
|
|
6717
9075
|
observeTurnFrames,
|
|
6718
9076
|
offerMemories,
|
|
6719
9077
|
offerSkills,
|
|
9078
|
+
parseTextActionProposalCommand,
|
|
9079
|
+
personaCatalogEntry,
|
|
9080
|
+
prepareActionProposal,
|
|
6720
9081
|
publishAgentDelegated,
|
|
6721
9082
|
publishAgentMemoryResolved,
|
|
6722
9083
|
publishAgentMemoryWritten,
|
|
@@ -6742,11 +9103,14 @@ var SqlTokenStreamSink = class {
|
|
|
6742
9103
|
rememberToolDefinition,
|
|
6743
9104
|
renderElicitationAnswers,
|
|
6744
9105
|
repairInstruction,
|
|
9106
|
+
resolveActionProposalApproval,
|
|
6745
9107
|
resolveElicitation,
|
|
6746
9108
|
resolveGateLookback,
|
|
6747
9109
|
resolveMemoryDigest,
|
|
6748
9110
|
resolveOutputGateMode,
|
|
9111
|
+
resolvePersonaAlias,
|
|
6749
9112
|
resolveSkillCatalog,
|
|
9113
|
+
resolveTextActionProposalDecision,
|
|
6750
9114
|
resolveToolTransientRetryNumbers,
|
|
6751
9115
|
rollupThreadUsage,
|
|
6752
9116
|
runAgentLoop,
|
|
@@ -6763,6 +9127,7 @@ var SqlTokenStreamSink = class {
|
|
|
6763
9127
|
skillInputSchema,
|
|
6764
9128
|
skillToolDefinition,
|
|
6765
9129
|
skillWriteVerdict,
|
|
9130
|
+
snapshotActionProposal,
|
|
6766
9131
|
stampToolKinds,
|
|
6767
9132
|
staticModelCatalog,
|
|
6768
9133
|
staticSkillProvider,
|
|
@@ -6773,8 +9138,18 @@ var SqlTokenStreamSink = class {
|
|
|
6773
9138
|
toolCallContext,
|
|
6774
9139
|
traceLlmTurn,
|
|
6775
9140
|
traceToolExecution,
|
|
9141
|
+
transitionActionProposalClaim,
|
|
9142
|
+
transitionActionProposalDecision,
|
|
9143
|
+
transitionActionProposalLease,
|
|
9144
|
+
transitionActionProposalSettlement,
|
|
9145
|
+
transitionActionProposalSupersession,
|
|
6776
9146
|
truncateDetailContent,
|
|
6777
9147
|
unwrapToolStepOutput,
|
|
9148
|
+
validateActionProposalCreation,
|
|
9149
|
+
validateActionProposalDiscoveryIndexBatch,
|
|
9150
|
+
validateActionProposalExpiryBatch,
|
|
9151
|
+
validateActionProposalListQuery,
|
|
9152
|
+
validateActionProposalWorkerClaim,
|
|
6778
9153
|
validateElicitationAnswer,
|
|
6779
9154
|
validateElicitationValue,
|
|
6780
9155
|
validateStructured,
|
|
@@ -6787,6 +9162,7 @@ var SqlTokenStreamSink = class {
|
|
|
6787
9162
|
withSkillTool,
|
|
6788
9163
|
withToolTimeout,
|
|
6789
9164
|
withTurnFrames,
|
|
9165
|
+
wrapToolPreflightDenied,
|
|
6790
9166
|
wrapToolStepOutput,
|
|
6791
9167
|
writeMemory
|
|
6792
9168
|
});
|