@jungjaehoon/mama-os 0.24.1 → 0.25.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/CHANGELOG.md +14 -0
- package/README.md +9 -6
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +8 -0
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/code-act/constants.js +2 -2
- package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
- package/dist/agent/code-act/host-bridge.js +37 -4
- package/dist/agent/code-act/host-bridge.js.map +1 -1
- package/dist/agent/code-act/type-definition-generator.d.ts.map +1 -1
- package/dist/agent/code-act/type-definition-generator.js +2 -4
- package/dist/agent/code-act/type-definition-generator.js.map +1 -1
- package/dist/agent/context-compile-service.d.ts +2 -0
- package/dist/agent/context-compile-service.d.ts.map +1 -1
- package/dist/agent/context-compile-service.js +26 -7
- package/dist/agent/context-compile-service.js.map +1 -1
- package/dist/agent/gateway-tool-executor.d.ts +2 -0
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +312 -18
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/gateway-tools.md +4 -3
- package/dist/agent/tool-registry.d.ts.map +1 -1
- package/dist/agent/tool-registry.js +9 -3
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +27 -6
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/operator-tasks-handler.d.ts.map +1 -1
- package/dist/api/operator-tasks-handler.js +23 -1
- package/dist/api/operator-tasks-handler.js.map +1 -1
- package/dist/cli/commands/start.d.ts +7 -3
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +113 -65
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts +2 -0
- package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
- package/dist/cli/runtime/agent-loop-init.js +37 -12
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/api-routes-init.js +3 -3
- package/dist/cli/runtime/api-routes-init.js.map +1 -1
- package/dist/cli/runtime/temporal-init.d.ts +28 -0
- package/dist/cli/runtime/temporal-init.d.ts.map +1 -0
- package/dist/cli/runtime/temporal-init.js +74 -0
- package/dist/cli/runtime/temporal-init.js.map +1 -0
- package/dist/db/migrations/operator-task-temporal.d.ts +8 -0
- package/dist/db/migrations/operator-task-temporal.d.ts.map +1 -0
- package/dist/db/migrations/operator-task-temporal.js +209 -0
- package/dist/db/migrations/operator-task-temporal.js.map +1 -0
- package/dist/envelope/enforcer.d.ts.map +1 -1
- package/dist/envelope/enforcer.js +6 -6
- package/dist/envelope/enforcer.js.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.d.ts.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.js +9 -4
- package/dist/multi-agent/dashboard-agent-persona.js.map +1 -1
- package/dist/operator/action-verifier.d.ts +23 -0
- package/dist/operator/action-verifier.d.ts.map +1 -1
- package/dist/operator/action-verifier.js +76 -0
- package/dist/operator/action-verifier.js.map +1 -1
- package/dist/operator/board-reconcile.d.ts.map +1 -1
- package/dist/operator/board-reconcile.js +3 -0
- package/dist/operator/board-reconcile.js.map +1 -1
- package/dist/operator/board-slot-instructions.d.ts +3 -3
- package/dist/operator/board-slot-instructions.d.ts.map +1 -1
- package/dist/operator/board-slot-instructions.js +17 -8
- package/dist/operator/board-slot-instructions.js.map +1 -1
- package/dist/operator/briefs.d.ts.map +1 -1
- package/dist/operator/briefs.js +3 -0
- package/dist/operator/briefs.js.map +1 -1
- package/dist/operator/task-ledger.d.ts +134 -8
- package/dist/operator/task-ledger.d.ts.map +1 -1
- package/dist/operator/task-ledger.js +1181 -74
- package/dist/operator/task-ledger.js.map +1 -1
- package/dist/operator/task-temporal.d.ts +21 -0
- package/dist/operator/task-temporal.d.ts.map +1 -0
- package/dist/operator/task-temporal.js +111 -0
- package/dist/operator/task-temporal.js.map +1 -0
- package/dist/operator/temporal-effect.d.ts +62 -0
- package/dist/operator/temporal-effect.d.ts.map +1 -0
- package/dist/operator/temporal-effect.js +71 -0
- package/dist/operator/temporal-effect.js.map +1 -0
- package/dist/operator/temporal-reconcile.d.ts +48 -0
- package/dist/operator/temporal-reconcile.d.ts.map +1 -0
- package/dist/operator/temporal-reconcile.js +215 -0
- package/dist/operator/temporal-reconcile.js.map +1 -0
- package/dist/operator/temporal-runtime.d.ts +54 -0
- package/dist/operator/temporal-runtime.d.ts.map +1 -0
- package/dist/operator/temporal-runtime.js +110 -0
- package/dist/operator/temporal-runtime.js.map +1 -0
- package/dist/operator/temporal-worker.d.ts +19 -0
- package/dist/operator/temporal-worker.d.ts.map +1 -0
- package/dist/operator/temporal-worker.js +105 -0
- package/dist/operator/temporal-worker.js.map +1 -0
- package/dist/operator/worker-run.d.ts +6 -2
- package/dist/operator/worker-run.d.ts.map +1 -1
- package/dist/operator/worker-run.js +14 -0
- package/dist/operator/worker-run.js.map +1 -1
- package/dist/operator/workorder-consumer.d.ts +27 -10
- package/dist/operator/workorder-consumer.d.ts.map +1 -1
- package/dist/operator/workorder-consumer.js +195 -14
- package/dist/operator/workorder-consumer.js.map +1 -1
- package/dist/operator/workorder-hooks.d.ts +3 -0
- package/dist/operator/workorder-hooks.d.ts.map +1 -1
- package/dist/operator/workorder-hooks.js +23 -0
- package/dist/operator/workorder-hooks.js.map +1 -1
- package/dist/operator/workorder-publishers.d.ts +10 -1
- package/dist/operator/workorder-publishers.d.ts.map +1 -1
- package/dist/operator/workorder-publishers.js +40 -3
- package/dist/operator/workorder-publishers.js.map +1 -1
- package/package.json +1 -1
- package/public/ui/assets/{index-OSgiwL24.js → index-BDXDGEV6.js} +15 -15
- package/public/ui/assets/index-po2tN0xq.css +1 -0
- package/public/ui/index.html +2 -2
- package/public/ui/assets/index-CKOJQYXA.css +0 -1
|
@@ -74,6 +74,61 @@ const managed_agent_validation_js_1 = require("./managed-agent-validation.js");
|
|
|
74
74
|
const delegation_executor_js_1 = require("./delegation-executor.js");
|
|
75
75
|
const index_js_1 = require("../envelope/index.js");
|
|
76
76
|
const wiki_publish_adapter_js_1 = require("../wiki-artifacts/wiki-publish-adapter.js");
|
|
77
|
+
function serializeTaskToolRecord(task) {
|
|
78
|
+
return {
|
|
79
|
+
...task,
|
|
80
|
+
due_at: task.dueAt === null ? null : new Date(task.dueAt).toISOString(),
|
|
81
|
+
deadline_offset_minutes: task.deadlineOffsetMinutes,
|
|
82
|
+
temporal_epoch: task.temporalEpoch,
|
|
83
|
+
temporal_reconciled_occurrence_key: task.temporalReconciledOccurrenceKey,
|
|
84
|
+
last_temporal_checked_at: task.lastTemporalCheckedAt,
|
|
85
|
+
next_temporal_check_at: task.nextTemporalCheckAt,
|
|
86
|
+
last_temporal_attempt_id: task.lastTemporalAttemptId,
|
|
87
|
+
temporal_state: task.temporalState,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function temporalContextPacketBinding(context) {
|
|
91
|
+
return `temporal:${context.taskId}:${context.generationKey}`;
|
|
92
|
+
}
|
|
93
|
+
function bindTemporalContextPacketTask(context, task) {
|
|
94
|
+
if (typeof task !== 'string' || task.trim().length === 0) {
|
|
95
|
+
const error = new Error('task is required.');
|
|
96
|
+
error.code = 'context_compile_input_invalid';
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
return `${temporalContextPacketBinding(context)}\n${task}`;
|
|
100
|
+
}
|
|
101
|
+
function temporalIdentifierRef(value) {
|
|
102
|
+
return `sha256:${(0, crypto_1.createHash)('sha256').update(value).digest('hex')}`;
|
|
103
|
+
}
|
|
104
|
+
function temporalPacketRawSourcesWithinBoundSource(context, sourceRefs) {
|
|
105
|
+
const rawRefs = sourceRefs.filter((value) => typeof value === 'object' &&
|
|
106
|
+
value !== null &&
|
|
107
|
+
!Array.isArray(value) &&
|
|
108
|
+
value.kind === 'raw');
|
|
109
|
+
if (!context.sourceChannel) {
|
|
110
|
+
return rawRefs.length === 0;
|
|
111
|
+
}
|
|
112
|
+
return rawRefs.every((ref) => {
|
|
113
|
+
const eventMatches = !context.sourceEventId ||
|
|
114
|
+
[ref.raw_id, ref.source_id].some((value) => typeof value === 'string' && temporalIdentifierRef(value) === context.sourceEventId);
|
|
115
|
+
const channelMatches = !context.sourceChannel ||
|
|
116
|
+
(typeof ref.connector === 'string' &&
|
|
117
|
+
typeof ref.channel_id === 'string' &&
|
|
118
|
+
temporalIdentifierRef(`${ref.connector}:${ref.channel_id}`) === context.sourceChannel);
|
|
119
|
+
return eventMatches && channelMatches;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function temporalPacketReferencesBoundSource(context, sourceRefs) {
|
|
123
|
+
const hasRawReference = sourceRefs.some((value) => typeof value === 'object' &&
|
|
124
|
+
value !== null &&
|
|
125
|
+
!Array.isArray(value) &&
|
|
126
|
+
value.kind === 'raw');
|
|
127
|
+
if (context.sourceEventId || context.sourceChannel) {
|
|
128
|
+
return hasRawReference && temporalPacketRawSourcesWithinBoundSource(context, sourceRefs);
|
|
129
|
+
}
|
|
130
|
+
return temporalPacketRawSourcesWithinBoundSource(context, sourceRefs);
|
|
131
|
+
}
|
|
77
132
|
const { DebugLogger } = debugLogger;
|
|
78
133
|
const securityLogger = new DebugLogger('SecurityAudit');
|
|
79
134
|
const TRUTHY_ENV_VALUES = new Set(['1', 'true', 'yes', 'on']);
|
|
@@ -114,6 +169,48 @@ const MEMORY_SCOPE_AUDIT_TOOLS = new Set([
|
|
|
114
169
|
'mama_add',
|
|
115
170
|
'mama_ingest',
|
|
116
171
|
]);
|
|
172
|
+
const TEMPORAL_WRITE_TOOLS = new Set([
|
|
173
|
+
'mama_save',
|
|
174
|
+
'context_compile',
|
|
175
|
+
'mama_update',
|
|
176
|
+
'mama_add',
|
|
177
|
+
'mama_ingest',
|
|
178
|
+
'report_publish',
|
|
179
|
+
'report_request',
|
|
180
|
+
'workorder_request',
|
|
181
|
+
'wiki_publish',
|
|
182
|
+
'obsidian',
|
|
183
|
+
'task_create',
|
|
184
|
+
'task_update',
|
|
185
|
+
'contract_no_update',
|
|
186
|
+
'task_temporal_reconcile',
|
|
187
|
+
'Write',
|
|
188
|
+
'Bash',
|
|
189
|
+
'discord_send',
|
|
190
|
+
'slack_send',
|
|
191
|
+
'telegram_send',
|
|
192
|
+
'webchat_send',
|
|
193
|
+
'delegate',
|
|
194
|
+
'os_add_bot',
|
|
195
|
+
'os_set_permissions',
|
|
196
|
+
'os_set_model',
|
|
197
|
+
'os_restart_bot',
|
|
198
|
+
'os_stop_bot',
|
|
199
|
+
'agent_update',
|
|
200
|
+
'agent_create',
|
|
201
|
+
'viewer_navigate',
|
|
202
|
+
'viewer_notify',
|
|
203
|
+
'save_integration_token',
|
|
204
|
+
'browser_navigate',
|
|
205
|
+
'browser_screenshot',
|
|
206
|
+
'browser_click',
|
|
207
|
+
'browser_type',
|
|
208
|
+
'browser_scroll',
|
|
209
|
+
'browser_evaluate',
|
|
210
|
+
'browser_pdf',
|
|
211
|
+
'browser_close',
|
|
212
|
+
'agent_test',
|
|
213
|
+
]);
|
|
117
214
|
const MEMORY_READ_PERMISSION_BEFORE_ENVELOPE_TOOLS = new Set([
|
|
118
215
|
'mama_save',
|
|
119
216
|
'mama_search',
|
|
@@ -284,6 +381,7 @@ class GatewayToolExecutor {
|
|
|
284
381
|
envelopeIssuanceMode;
|
|
285
382
|
metricsStore;
|
|
286
383
|
contextCompileService;
|
|
384
|
+
temporalContextPacketLookup;
|
|
287
385
|
currentContext = null;
|
|
288
386
|
memoryAgentProcessManager = null;
|
|
289
387
|
agentProcessManager = null;
|
|
@@ -378,6 +476,8 @@ class GatewayToolExecutor {
|
|
|
378
476
|
sourceMessageRef: executionContext?.sourceMessageRef,
|
|
379
477
|
modelRunId: executionContext?.modelRunId ?? null,
|
|
380
478
|
gatewayCallId: executionContext?.gatewayCallId,
|
|
479
|
+
workorderAttemptId: executionContext?.workorderAttemptId,
|
|
480
|
+
temporalWorkContext: executionContext?.temporalWorkContext,
|
|
381
481
|
signal: executionContext?.signal,
|
|
382
482
|
parentToolName: executionContext?.parentToolName,
|
|
383
483
|
backgroundTasks: executionContext?.backgroundTasks,
|
|
@@ -412,6 +512,10 @@ class GatewayToolExecutor {
|
|
|
412
512
|
sourceMessageRef: active.sourceMessageRef ?? fallback.sourceMessageRef,
|
|
413
513
|
modelRunId: active.modelRunId ?? fallback.modelRunId,
|
|
414
514
|
gatewayCallId: active.gatewayCallId ?? fallback.gatewayCallId,
|
|
515
|
+
// Never merged from fallback - attempt identity is issued for one claimed run only.
|
|
516
|
+
workorderAttemptId: active.workorderAttemptId,
|
|
517
|
+
// Never merged from fallback - temporal authority belongs to one claimed run only.
|
|
518
|
+
temporalWorkContext: active.temporalWorkContext,
|
|
415
519
|
signal: active.signal,
|
|
416
520
|
parentToolName: active.parentToolName ?? fallback.parentToolName,
|
|
417
521
|
backgroundTasks: active.backgroundTasks ?? fallback.backgroundTasks,
|
|
@@ -448,6 +552,23 @@ class GatewayToolExecutor {
|
|
|
448
552
|
const activeContext = this.normalizeExecutionContext(executionContext);
|
|
449
553
|
return this.executionContextStorage.run(activeContext, fn);
|
|
450
554
|
}
|
|
555
|
+
requireActiveTemporalAuthority(toolName) {
|
|
556
|
+
const context = this.getExecutionState().temporalWorkContext;
|
|
557
|
+
if (toolName === 'task_temporal_reconcile' && !context) {
|
|
558
|
+
throw new types_js_1.AgentError('task_temporal_reconcile requires an active host-issued temporal work context', 'WORKORDER_SUPERSEDED', undefined, false);
|
|
559
|
+
}
|
|
560
|
+
if (!context)
|
|
561
|
+
return null;
|
|
562
|
+
if (!this.taskLedger) {
|
|
563
|
+
throw new types_js_1.AgentError('Temporal work authority cannot be checked because the task ledger is unavailable', 'WORKORDER_SUPERSEDED', undefined, false);
|
|
564
|
+
}
|
|
565
|
+
try {
|
|
566
|
+
return this.taskLedger.assertTemporalWorkContextActive(context);
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
throw new types_js_1.AgentError('Temporal workorder authority is no longer active', 'WORKORDER_SUPERSEDED', undefined, false);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
451
572
|
setCurrentAgentContext(agentId, source, channelId) {
|
|
452
573
|
this.currentAgentId = agentId;
|
|
453
574
|
this.currentSource = source;
|
|
@@ -599,6 +720,20 @@ class GatewayToolExecutor {
|
|
|
599
720
|
this.envelopeIssuanceMode = options.envelopeIssuanceMode ?? 'enabled';
|
|
600
721
|
this.metricsStore = options.metricsStore ?? null;
|
|
601
722
|
this.contextCompileService = options.contextCompileService;
|
|
723
|
+
this.temporalContextPacketLookup =
|
|
724
|
+
options.temporalContextPacketLookup ??
|
|
725
|
+
(async (input) => {
|
|
726
|
+
const packet = (0, mama_core_1.getContextPacketForTrustedUse)(await getContextPacketLookupAdapter(), input);
|
|
727
|
+
if (!packet)
|
|
728
|
+
return null;
|
|
729
|
+
return {
|
|
730
|
+
packet_id: packet.packet_id,
|
|
731
|
+
task: packet.task,
|
|
732
|
+
packet_json: packet.packet_json,
|
|
733
|
+
source_refs: packet.source_refs,
|
|
734
|
+
created_at: packet.created_at,
|
|
735
|
+
};
|
|
736
|
+
});
|
|
602
737
|
this.wikiPublishAdapter = options.wikiPublishAdapter ?? null;
|
|
603
738
|
this.browserTool = (0, browser_tool_js_1.getBrowserTool)({
|
|
604
739
|
screenshotDir: (0, path_1.join)(process.env.HOME || '', '.mama', 'workspace', 'media', 'outbound'),
|
|
@@ -798,10 +933,8 @@ class GatewayToolExecutor {
|
|
|
798
933
|
this.logEnvelopeActivity(ctx, 'envelope_violation', toolName, err.message);
|
|
799
934
|
const denial = {
|
|
800
935
|
success: false,
|
|
801
|
-
error: err.
|
|
936
|
+
error: `[${err.code}] Envelope policy denied this tool call`,
|
|
802
937
|
code: err.code,
|
|
803
|
-
envelope_hash: ctx.envelope.envelope_hash,
|
|
804
|
-
...err.metadata,
|
|
805
938
|
};
|
|
806
939
|
return denial;
|
|
807
940
|
}
|
|
@@ -893,43 +1026,79 @@ class GatewayToolExecutor {
|
|
|
893
1026
|
const gatewayCallId = baseCtx.gatewayCallId ?? `gw_${(0, crypto_1.randomUUID)().replace(/-/g, '')}`;
|
|
894
1027
|
const ctx = { ...baseCtx, gatewayCallId };
|
|
895
1028
|
const effectiveInput = this.applyEnvelopeScopedReadDefaults(toolName, input, ctx);
|
|
896
|
-
const
|
|
1029
|
+
const computedScopeAudit = this.computeScopeAuditFields(toolName, effectiveInput, ctx);
|
|
1030
|
+
const scopeAudit = ctx.temporalWorkContext
|
|
1031
|
+
? {
|
|
1032
|
+
requestedScopes: null,
|
|
1033
|
+
envelopeScopesSnapshot: null,
|
|
1034
|
+
mismatch: computedScopeAudit.mismatch,
|
|
1035
|
+
}
|
|
1036
|
+
: {
|
|
1037
|
+
...computedScopeAudit,
|
|
1038
|
+
requestedScopes: digestRequestedScopesForAudit(computedScopeAudit.requestedScopes),
|
|
1039
|
+
};
|
|
1040
|
+
if (ctx.temporalWorkContext && TEMPORAL_WRITE_TOOLS.has(toolName)) {
|
|
1041
|
+
await this.executionContextStorage.run(ctx, async () => {
|
|
1042
|
+
this.requireActiveTemporalAuthority(toolName);
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
897
1045
|
const traceState = await this.beginTraceIfNeeded(ctx, gatewayCallId);
|
|
898
1046
|
const activeCtx = traceState ? { ...ctx, modelRunId: traceState.modelRunId } : ctx;
|
|
899
1047
|
let result;
|
|
1048
|
+
let auditResult;
|
|
900
1049
|
try {
|
|
901
|
-
|
|
1050
|
+
const rawResult = await this.executionContextStorage.run(activeCtx, () => this.executeWithEnvelopeAndPermissions(toolName, effectiveInput, gatewayCallId));
|
|
1051
|
+
if (activeCtx.temporalWorkContext &&
|
|
1052
|
+
toolName !== 'task_temporal_reconcile' &&
|
|
1053
|
+
toolName !== 'code_act') {
|
|
1054
|
+
await this.executionContextStorage.run(activeCtx, async () => {
|
|
1055
|
+
this.requireActiveTemporalAuthority(toolName);
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
const shouldSanitizeAuditFailure = Boolean(activeCtx.temporalWorkContext) ||
|
|
1059
|
+
toolName === 'context_compile' ||
|
|
1060
|
+
toolName === 'code_act';
|
|
1061
|
+
auditResult = shouldSanitizeAuditFailure
|
|
1062
|
+
? sanitizeGatewayFailureResult(rawResult, Boolean(activeCtx.temporalWorkContext))
|
|
1063
|
+
: rawResult;
|
|
1064
|
+
result = activeCtx.temporalWorkContext ? auditResult : rawResult;
|
|
902
1065
|
activeCtx.signal?.throwIfAborted();
|
|
903
1066
|
}
|
|
904
1067
|
catch (error) {
|
|
905
|
-
|
|
1068
|
+
const shouldSanitizeAuditFailure = Boolean(activeCtx.temporalWorkContext) ||
|
|
1069
|
+
toolName === 'context_compile' ||
|
|
1070
|
+
toolName === 'code_act';
|
|
1071
|
+
const auditError = shouldSanitizeAuditFailure
|
|
1072
|
+
? sanitizeGatewayError(error, Boolean(activeCtx.temporalWorkContext))
|
|
1073
|
+
: error;
|
|
1074
|
+
await this.appendToolTraceIfNeeded(traceState, activeCtx, toolName, undefined, Date.now() - startedAt, gatewayCallId, auditError).catch((appendError) => {
|
|
906
1075
|
securityLogger.warn('[model-run] failed to append failed tool trace before finalization', appendError);
|
|
907
1076
|
});
|
|
908
|
-
await this.failDirectModelRunIfNeeded(traceState, toolName,
|
|
1077
|
+
await this.failDirectModelRunIfNeeded(traceState, toolName, auditError).catch((finalizationError) => {
|
|
909
1078
|
securityLogger.warn('[model-run] failed to finalize failed direct model run', finalizationError);
|
|
910
1079
|
});
|
|
911
|
-
this.logGatewayToolCall(activeCtx, toolName, undefined, Date.now() - startedAt, scopeAudit, gatewayCallId,
|
|
1080
|
+
this.logGatewayToolCall(activeCtx, toolName, undefined, Date.now() - startedAt, scopeAudit, gatewayCallId, auditError);
|
|
912
1081
|
if (scopeAudit.mismatch) {
|
|
913
1082
|
this.alarmScopeMismatch(activeCtx, toolName);
|
|
914
1083
|
}
|
|
915
|
-
throw error;
|
|
1084
|
+
throw activeCtx.temporalWorkContext ? auditError : error;
|
|
916
1085
|
}
|
|
917
1086
|
try {
|
|
918
1087
|
try {
|
|
919
|
-
await this.appendToolTraceIfNeeded(traceState, activeCtx, toolName,
|
|
1088
|
+
await this.appendToolTraceIfNeeded(traceState, activeCtx, toolName, auditResult, Date.now() - startedAt, gatewayCallId);
|
|
920
1089
|
}
|
|
921
1090
|
finally {
|
|
922
|
-
await this.completeDirectModelRunIfNeeded(traceState, toolName,
|
|
1091
|
+
await this.completeDirectModelRunIfNeeded(traceState, toolName, auditResult);
|
|
923
1092
|
}
|
|
924
1093
|
}
|
|
925
1094
|
catch (postRunError) {
|
|
926
|
-
this.logGatewayToolCall(activeCtx, toolName,
|
|
1095
|
+
this.logGatewayToolCall(activeCtx, toolName, auditResult, Date.now() - startedAt, scopeAudit, gatewayCallId, postRunError);
|
|
927
1096
|
if (scopeAudit.mismatch) {
|
|
928
1097
|
this.alarmScopeMismatch(activeCtx, toolName);
|
|
929
1098
|
}
|
|
930
1099
|
throw postRunError;
|
|
931
1100
|
}
|
|
932
|
-
this.logGatewayToolCall(activeCtx, toolName,
|
|
1101
|
+
this.logGatewayToolCall(activeCtx, toolName, auditResult, Date.now() - startedAt, scopeAudit, gatewayCallId);
|
|
933
1102
|
if (scopeAudit.mismatch) {
|
|
934
1103
|
this.alarmScopeMismatch(activeCtx, toolName);
|
|
935
1104
|
}
|
|
@@ -1277,6 +1446,9 @@ class GatewayToolExecutor {
|
|
|
1277
1446
|
gateway_call_id: gatewayCallId,
|
|
1278
1447
|
...(resultCode ? { code: resultCode } : {}),
|
|
1279
1448
|
...(ctx?.parentToolName ? { parent: ctx.parentToolName } : {}),
|
|
1449
|
+
...(ctx?.workorderAttemptId !== undefined
|
|
1450
|
+
? { workorder_attempt_id: ctx.workorderAttemptId }
|
|
1451
|
+
: {}),
|
|
1280
1452
|
},
|
|
1281
1453
|
});
|
|
1282
1454
|
}
|
|
@@ -1337,6 +1509,7 @@ class GatewayToolExecutor {
|
|
|
1337
1509
|
};
|
|
1338
1510
|
}
|
|
1339
1511
|
}
|
|
1512
|
+
this.requireActiveTemporalAuthority(toolName);
|
|
1340
1513
|
const envelopeDenied = this.enforceEnvelopeForToolCall(toolName, input);
|
|
1341
1514
|
if (envelopeDenied) {
|
|
1342
1515
|
return envelopeDenied;
|
|
@@ -1752,6 +1925,14 @@ class GatewayToolExecutor {
|
|
|
1752
1925
|
if (!slotsInput || typeof slotsInput !== 'object') {
|
|
1753
1926
|
throw new types_js_1.AgentError('report_publish requires slots object', 'TOOL_ERROR', undefined, false);
|
|
1754
1927
|
}
|
|
1928
|
+
if (this.getExecutionState().temporalWorkContext) {
|
|
1929
|
+
const slotNames = Object.keys(slotsInput);
|
|
1930
|
+
if (slotNames.length !== 1 ||
|
|
1931
|
+
slotNames[0] !== 'pipeline' ||
|
|
1932
|
+
typeof slotsInput.pipeline !== 'string') {
|
|
1933
|
+
throw new types_js_1.AgentError('Temporal report_publish accepts exactly the host-derived pipeline slot', 'TOOL_ERROR', undefined, false);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1755
1936
|
// Stage-2 shadow seam: a per-run capture override takes precedence
|
|
1756
1937
|
// over the global singleton (capture runs never touch the live store).
|
|
1757
1938
|
const activePublisher = this.getExecutionState().reportPublisherOverride ?? this.reportPublisher;
|
|
@@ -1926,16 +2107,29 @@ class GatewayToolExecutor {
|
|
|
1926
2107
|
if (!this.taskLedger) {
|
|
1927
2108
|
return { success: false, error: 'Task ledger not configured' };
|
|
1928
2109
|
}
|
|
2110
|
+
const temporalContext = this.getExecutionState().temporalWorkContext;
|
|
2111
|
+
if (temporalContext) {
|
|
2112
|
+
const boundTask = this.taskLedger.getById(temporalContext.taskId);
|
|
2113
|
+
if (!boundTask) {
|
|
2114
|
+
throw new types_js_1.AgentError('Host-bound temporal owner task is unavailable', 'WORKORDER_SUPERSEDED', undefined, false);
|
|
2115
|
+
}
|
|
2116
|
+
return {
|
|
2117
|
+
success: true,
|
|
2118
|
+
tasks: [serializeTaskToolRecord(boundTask)],
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
1929
2121
|
const listInput = input;
|
|
1930
2122
|
return {
|
|
1931
2123
|
success: true,
|
|
1932
|
-
tasks: this.taskLedger
|
|
2124
|
+
tasks: this.taskLedger
|
|
2125
|
+
.list({
|
|
1933
2126
|
status: listInput.status,
|
|
1934
2127
|
channel: listInput.channel,
|
|
1935
2128
|
search: listInput.search,
|
|
1936
2129
|
limit: listInput.limit,
|
|
1937
2130
|
order: listInput.order ?? 'deadline_priority',
|
|
1938
|
-
})
|
|
2131
|
+
})
|
|
2132
|
+
.map(serializeTaskToolRecord),
|
|
1939
2133
|
};
|
|
1940
2134
|
}
|
|
1941
2135
|
case 'task_create': {
|
|
@@ -1944,7 +2138,7 @@ class GatewayToolExecutor {
|
|
|
1944
2138
|
}
|
|
1945
2139
|
return {
|
|
1946
2140
|
success: true,
|
|
1947
|
-
task: this.taskLedger.create(input),
|
|
2141
|
+
task: serializeTaskToolRecord(this.taskLedger.create(input)),
|
|
1948
2142
|
};
|
|
1949
2143
|
}
|
|
1950
2144
|
case 'task_update': {
|
|
@@ -1959,7 +2153,59 @@ class GatewayToolExecutor {
|
|
|
1959
2153
|
}
|
|
1960
2154
|
return {
|
|
1961
2155
|
success: true,
|
|
1962
|
-
task: this.taskLedger.update(id, patch),
|
|
2156
|
+
task: serializeTaskToolRecord(this.taskLedger.update(id, patch)),
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
case 'task_temporal_reconcile': {
|
|
2160
|
+
if (!this.taskLedger) {
|
|
2161
|
+
return { success: false, error: 'Task ledger not configured' };
|
|
2162
|
+
}
|
|
2163
|
+
const context = this.getExecutionState().temporalWorkContext;
|
|
2164
|
+
if (!context) {
|
|
2165
|
+
throw new types_js_1.AgentError('task_temporal_reconcile requires trusted temporal context', 'WORKORDER_SUPERSEDED', undefined, false);
|
|
2166
|
+
}
|
|
2167
|
+
const contextPacketId = input.context_packet_id;
|
|
2168
|
+
if (typeof contextPacketId !== 'string' || contextPacketId.trim().length === 0) {
|
|
2169
|
+
throw new types_js_1.AgentError('task_temporal_reconcile requires a fresh context_packet_id', 'TOOL_ERROR', undefined, false);
|
|
2170
|
+
}
|
|
2171
|
+
const executionState = this.getExecutionState();
|
|
2172
|
+
if (!executionState.envelope || !executionState.modelRunId) {
|
|
2173
|
+
throw new types_js_1.AgentError('task_temporal_reconcile evidence requires an active envelope and model run', 'TOOL_ERROR', undefined, false);
|
|
2174
|
+
}
|
|
2175
|
+
const packet = await this.temporalContextPacketLookup({
|
|
2176
|
+
packetId: contextPacketId,
|
|
2177
|
+
envelopeHash: executionState.envelope.envelope_hash,
|
|
2178
|
+
callerModelRunId: executionState.modelRunId,
|
|
2179
|
+
});
|
|
2180
|
+
if (!packet || packet.packet_id !== contextPacketId) {
|
|
2181
|
+
throw new types_js_1.AgentError('task_temporal_reconcile context packet is unavailable', 'TOOL_ERROR', undefined, false);
|
|
2182
|
+
}
|
|
2183
|
+
const attempt = this.taskLedger.inspectTemporalAttempt(context.attemptId);
|
|
2184
|
+
if (!Number.isSafeInteger(packet.created_at) ||
|
|
2185
|
+
packet.created_at < attempt.workOrder.updatedAt) {
|
|
2186
|
+
throw new types_js_1.AgentError('task_temporal_reconcile context packet predates the active attempt', 'TOOL_ERROR', undefined, false);
|
|
2187
|
+
}
|
|
2188
|
+
const effectInput = input;
|
|
2189
|
+
if (effectInput.outcome !== 'deferred' &&
|
|
2190
|
+
(!Array.isArray(packet.source_refs) || packet.source_refs.length === 0)) {
|
|
2191
|
+
throw new types_js_1.AgentError('task_temporal_reconcile requires source-backed fresh evidence', 'TOOL_ERROR', undefined, false);
|
|
2192
|
+
}
|
|
2193
|
+
if (!packet.task.startsWith(`${temporalContextPacketBinding(context)}\n`) ||
|
|
2194
|
+
(effectInput.outcome === 'deferred'
|
|
2195
|
+
? Array.isArray(packet.source_refs) &&
|
|
2196
|
+
packet.source_refs.length > 0 &&
|
|
2197
|
+
!temporalPacketReferencesBoundSource(context, packet.source_refs)
|
|
2198
|
+
: !temporalPacketReferencesBoundSource(context, packet.source_refs))) {
|
|
2199
|
+
throw new types_js_1.AgentError('task_temporal_reconcile context packet is not bound to the active task source', 'TOOL_ERROR', undefined, false);
|
|
2200
|
+
}
|
|
2201
|
+
const evidence = {
|
|
2202
|
+
contextPacketId,
|
|
2203
|
+
contextPacketSha256: (0, crypto_1.createHash)('sha256').update(packet.packet_json).digest('hex'),
|
|
2204
|
+
};
|
|
2205
|
+
const { context_packet_id: _contextPacketId, ...trustedEffectInput } = effectInput;
|
|
2206
|
+
return {
|
|
2207
|
+
success: true,
|
|
2208
|
+
receipt: this.taskLedger.applyTemporalEffect(context, trustedEffectInput, evidence),
|
|
1963
2209
|
};
|
|
1964
2210
|
}
|
|
1965
2211
|
case 'schedule_upcoming': {
|
|
@@ -3423,13 +3669,26 @@ class GatewayToolExecutor {
|
|
|
3423
3669
|
};
|
|
3424
3670
|
}
|
|
3425
3671
|
try {
|
|
3672
|
+
const temporalContext = ctx.temporalWorkContext;
|
|
3673
|
+
const effectiveInput = temporalContext
|
|
3674
|
+
? { ...input, task: bindTemporalContextPacketTask(temporalContext, input.task) }
|
|
3675
|
+
: input;
|
|
3426
3676
|
const result = await this.contextCompileService.compileAndPersistContext({
|
|
3427
3677
|
caller: 'gateway',
|
|
3428
3678
|
envelope: ctx.envelope,
|
|
3429
3679
|
modelRunId: ctx.modelRunId ?? null,
|
|
3430
|
-
input,
|
|
3680
|
+
input: effectiveInput,
|
|
3431
3681
|
signal: ctx.signal,
|
|
3682
|
+
beforePersist: temporalContext
|
|
3683
|
+
? () => {
|
|
3684
|
+
this.requireActiveTemporalAuthority('context_compile');
|
|
3685
|
+
}
|
|
3686
|
+
: undefined,
|
|
3432
3687
|
});
|
|
3688
|
+
if (temporalContext &&
|
|
3689
|
+
!temporalPacketRawSourcesWithinBoundSource(temporalContext, result.packet.source_refs)) {
|
|
3690
|
+
throw new Error('context_compile packet exceeds the active temporal task source');
|
|
3691
|
+
}
|
|
3433
3692
|
return {
|
|
3434
3693
|
success: true,
|
|
3435
3694
|
packet: result.packet,
|
|
@@ -3565,6 +3824,15 @@ function isMemoryScope(value) {
|
|
|
3565
3824
|
function memoryScopeKey(scope) {
|
|
3566
3825
|
return `${scope.kind}:${scope.id}`;
|
|
3567
3826
|
}
|
|
3827
|
+
function digestRequestedScopesForAudit(scopes) {
|
|
3828
|
+
if (!scopes) {
|
|
3829
|
+
return null;
|
|
3830
|
+
}
|
|
3831
|
+
return scopes.map((scope) => ({
|
|
3832
|
+
kind: scope.kind,
|
|
3833
|
+
id: `sha256:${(0, crypto_1.createHash)('sha256').update(scope.id).digest('hex')}`,
|
|
3834
|
+
}));
|
|
3835
|
+
}
|
|
3568
3836
|
function getFailureMessage(result) {
|
|
3569
3837
|
if (!result || result.success !== false) {
|
|
3570
3838
|
return undefined;
|
|
@@ -3573,4 +3841,30 @@ function getFailureMessage(result) {
|
|
|
3573
3841
|
const message = record.error ?? record.message ?? 'Tool returned success:false';
|
|
3574
3842
|
return String(message);
|
|
3575
3843
|
}
|
|
3844
|
+
function gatewayFailureRef(value, temporal) {
|
|
3845
|
+
const digest = (0, crypto_1.createHash)('sha256').update(value).digest('hex');
|
|
3846
|
+
const label = temporal ? 'temporal_tool_failed' : 'gateway_tool_failed';
|
|
3847
|
+
return `${label};sha256=${digest};length=${value.length}`;
|
|
3848
|
+
}
|
|
3849
|
+
function sanitizeGatewayFailureResult(result, temporal) {
|
|
3850
|
+
const failure = getFailureMessage(result);
|
|
3851
|
+
if (!failure) {
|
|
3852
|
+
return result;
|
|
3853
|
+
}
|
|
3854
|
+
const record = result;
|
|
3855
|
+
return {
|
|
3856
|
+
success: false,
|
|
3857
|
+
error: gatewayFailureRef(failure, temporal),
|
|
3858
|
+
...(typeof record.code === 'string' ? { code: record.code } : {}),
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
function sanitizeGatewayError(error, temporal) {
|
|
3862
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3863
|
+
if (error instanceof types_js_1.AgentError) {
|
|
3864
|
+
return new types_js_1.AgentError(error.code === 'WORKORDER_SUPERSEDED'
|
|
3865
|
+
? 'Temporal workorder authority is no longer active'
|
|
3866
|
+
: gatewayFailureRef(message, temporal), error.code, undefined, error.retryable);
|
|
3867
|
+
}
|
|
3868
|
+
return new Error(gatewayFailureRef(message, temporal));
|
|
3869
|
+
}
|
|
3576
3870
|
//# sourceMappingURL=gateway-tool-executor.js.map
|