@jangts/agent-core 0.3.5 → 0.3.6
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 +21 -0
- package/README.md +28 -26
- package/development/docs/api/README.en.md +2 -0
- package/development/docs/api/README.md +2 -0
- package/development/docs/api/observability.en.md +37 -11
- package/development/docs/api/observability.md +64 -11
- package/development/docs/api/reference.en.md +469 -348
- package/development/docs/api/reference.md +193 -137
- package/development/docs/api/types.en.md +1 -0
- package/development/docs/api/types.md +1 -0
- package/development/docs/api/workflow-views.en.md +64 -0
- package/development/docs/api/workflow-views.md +78 -0
- package/development/docs/api/workflow.en.md +6 -2
- package/development/docs/api/workflow.md +6 -2
- package/development/skills/agent-core-app/SKILL.md +12 -0
- package/dist/cjs/capabilities/invocation.js +21 -1
- package/dist/cjs/capabilities/tool-runtime.js +8 -1
- package/dist/cjs/capabilities/tools.js +12 -17
- package/dist/cjs/diagnostics/index.js +51 -3
- package/dist/cjs/diagnostics/native-sub-flow.js +106 -0
- package/dist/cjs/diagnostics/sub-flow.js +278 -32
- package/dist/cjs/execution/engine.js +3 -2
- package/dist/cjs/execution/events.js +5 -5
- package/dist/cjs/execution/reporting.js +18 -28
- package/dist/cjs/execution/workflow-chain.js +211 -0
- package/dist/cjs/execution/workflow-graph.js +72 -0
- package/dist/cjs/execution/workflow.js +34 -6
- package/dist/cjs/kits/aggregation.js +17 -14
- package/dist/cjs/kits/answering/checks.js +2 -1
- package/dist/cjs/kits/answering/flow.js +24 -21
- package/dist/cjs/kits/answering/tasks.js +25 -20
- package/dist/cjs/kits/delivery.js +36 -24
- package/dist/cjs/kits/knowledge/catalog.js +33 -30
- package/dist/cjs/kits/policies.js +3 -2
- package/dist/cjs/kits/presentation/outputs.js +2 -1
- package/dist/cjs/kits/retrieval.js +7 -1
- package/dist/cjs/kits/tools.js +1 -0
- package/dist/cjs/model/decision-retry.js +2 -1
- package/dist/cjs/model/runner.js +20 -5
- package/dist/cjs/structs/execution/workflow-views.js +2 -0
- package/dist/cjs/support/context/nodes.js +48 -45
- package/dist/cjs/support/context/processing.js +6 -3
- package/dist/cjs/utils/invocation.js +1 -0
- package/dist/esm/capabilities/invocation.js +21 -1
- package/dist/esm/capabilities/tool-runtime.js +8 -1
- package/dist/esm/capabilities/tools.js +12 -17
- package/dist/esm/diagnostics/index.d.ts +1 -0
- package/dist/esm/diagnostics/index.js +48 -2
- package/dist/esm/diagnostics/native-sub-flow.d.ts +94 -0
- package/dist/esm/diagnostics/native-sub-flow.js +101 -0
- package/dist/esm/diagnostics/sub-flow.d.ts +56 -4
- package/dist/esm/diagnostics/sub-flow.js +271 -32
- package/dist/esm/execution/engine.d.ts +1 -0
- package/dist/esm/execution/engine.js +3 -2
- package/dist/esm/execution/events.js +5 -5
- package/dist/esm/execution/reporting.d.ts +6 -12
- package/dist/esm/execution/reporting.js +19 -29
- package/dist/esm/execution/workflow-chain.d.ts +3 -0
- package/dist/esm/execution/workflow-chain.js +208 -0
- package/dist/esm/execution/workflow-graph.d.ts +7 -0
- package/dist/esm/execution/workflow-graph.js +68 -0
- package/dist/esm/execution/workflow.d.ts +6 -0
- package/dist/esm/execution/workflow.js +34 -6
- package/dist/esm/kits/aggregation.d.ts +1 -1
- package/dist/esm/kits/aggregation.js +17 -14
- package/dist/esm/kits/answering/checks.js +2 -1
- package/dist/esm/kits/answering/flow.js +24 -21
- package/dist/esm/kits/answering/tasks.js +25 -20
- package/dist/esm/kits/delivery.d.ts +0 -9
- package/dist/esm/kits/delivery.js +36 -24
- package/dist/esm/kits/knowledge/catalog.js +33 -30
- package/dist/esm/kits/policies.d.ts +1 -1
- package/dist/esm/kits/policies.js +3 -2
- package/dist/esm/kits/presentation/outputs.js +2 -1
- package/dist/esm/kits/retrieval.js +7 -1
- package/dist/esm/kits/tools.js +1 -0
- package/dist/esm/model/decision-retry.d.ts +2 -0
- package/dist/esm/model/decision-retry.js +2 -1
- package/dist/esm/model/runner.d.ts +2 -0
- package/dist/esm/model/runner.js +20 -5
- package/dist/esm/structs/capabilities/invocation.d.ts +2 -0
- package/dist/esm/structs/capabilities/tools.d.ts +7 -3
- package/dist/esm/structs/common.d.ts +2 -0
- package/dist/esm/structs/debug.d.ts +36 -20
- package/dist/esm/structs/execution/workflow-views.d.ts +123 -0
- package/dist/esm/structs/execution/workflow-views.js +1 -0
- package/dist/esm/structs/execution/workflow.d.ts +4 -3
- package/dist/esm/structs/index.d.ts +1 -0
- package/dist/esm/structs/model/runtime.d.ts +2 -0
- package/dist/esm/support/context/nodes.js +48 -45
- package/dist/esm/support/context/processing.js +6 -3
- package/dist/esm/utils/invocation.d.ts +1 -0
- package/dist/esm/utils/invocation.js +1 -0
- package/package.json +1 -1
- package/dist/cjs/utils/debug.js +0 -30
- package/dist/esm/utils/debug.d.ts +0 -27
- package/dist/esm/utils/debug.js +0 -27
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Delivery = void 0;
|
|
4
4
|
exports.defineDelivery = defineDelivery;
|
|
5
|
+
/**
|
|
6
|
+
* Delivery Kit: run an ordered, synchronous stage pipeline that ends with one result.
|
|
7
|
+
*
|
|
8
|
+
* Place in the package: an optional App-side delivery pipeline (for example formatting and
|
|
9
|
+
* sending one reply). The Kit owns ordering, cancellation checks and outcome validation; the
|
|
10
|
+
* stages, their state and the actual side effects belong to the App.
|
|
11
|
+
*
|
|
12
|
+
* Exports: `defineDelivery`, `Delivery`, and the delivery option/outcome types.
|
|
13
|
+
*/
|
|
14
|
+
const native_sub_flow_js_1 = require("../diagnostics/native-sub-flow.js");
|
|
5
15
|
const synchronous_js_1 = require("../utils/synchronous.js");
|
|
6
16
|
/**
|
|
7
17
|
* Compile a delivery pipeline from its declared stages.
|
|
@@ -42,33 +52,35 @@ function defineDelivery(options) {
|
|
|
42
52
|
* handler results.
|
|
43
53
|
*/
|
|
44
54
|
deliver(input, execution) {
|
|
45
|
-
|
|
46
|
-
const state = (0, synchronous_js_1.synchronous)(createState(input, execution), 'Delivery state creation must be synchronous');
|
|
47
|
-
const context = {
|
|
48
|
-
...execution,
|
|
49
|
-
signal: execution.signal,
|
|
50
|
-
diagnostics: execution.diagnostics,
|
|
51
|
-
app: input,
|
|
52
|
-
};
|
|
53
|
-
for (const stage of stages) {
|
|
55
|
+
return (0, native_sub_flow_js_1.nativeSubFlowSync)(execution, 'delivery', 'delivery', () => {
|
|
54
56
|
execution.signal.throwIfAborted();
|
|
55
|
-
(0, synchronous_js_1.synchronous)(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
const state = (0, synchronous_js_1.synchronous)(createState(input, execution), 'Delivery state creation must be synchronous');
|
|
58
|
+
const context = {
|
|
59
|
+
...execution,
|
|
60
|
+
signal: execution.signal,
|
|
61
|
+
diagnostics: execution.diagnostics,
|
|
62
|
+
app: input,
|
|
63
|
+
};
|
|
64
|
+
for (const stage of stages) {
|
|
65
|
+
execution.signal.throwIfAborted();
|
|
66
|
+
(0, synchronous_js_1.synchronous)(beforeStage?.({ stageId: stage.id, state }, context), 'Delivery hooks must be synchronous');
|
|
67
|
+
execution.signal.throwIfAborted();
|
|
68
|
+
if (!stage.handle)
|
|
69
|
+
continue;
|
|
70
|
+
const outcome = (0, synchronous_js_1.synchronous)(stage.handle(state, context), 'Delivery handlers must be synchronous');
|
|
67
71
|
execution.signal.throwIfAborted();
|
|
68
|
-
|
|
72
|
+
if (!outcome ||
|
|
73
|
+
!['continue', 'complete'].includes(outcome.type) ||
|
|
74
|
+
(outcome.type === 'complete' && !('value' in outcome)))
|
|
75
|
+
throw new TypeError('Delivery handlers require explicit continue/complete');
|
|
76
|
+
if (outcome.type === 'complete') {
|
|
77
|
+
const value = outcome.value;
|
|
78
|
+
execution.signal.throwIfAborted();
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
69
81
|
}
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
throw (0, synchronous_js_1.synchronous)(missingResult(), 'Delivery errors must be synchronous');
|
|
83
|
+
});
|
|
72
84
|
},
|
|
73
85
|
});
|
|
74
86
|
}
|
|
@@ -10,6 +10,7 @@ exports.defineKnowledgeCatalog = defineKnowledgeCatalog;
|
|
|
10
10
|
*
|
|
11
11
|
* Exports: `defineKnowledgeCatalog`, and the knowledge document/read/snapshot types.
|
|
12
12
|
*/
|
|
13
|
+
const native_sub_flow_js_1 = require("../../diagnostics/native-sub-flow.js");
|
|
13
14
|
const catalog_js_1 = require("../../utils/catalog.js");
|
|
14
15
|
const sections_js_1 = require("./sections.js");
|
|
15
16
|
const observer_js_1 = require("../../utils/observer.js");
|
|
@@ -68,37 +69,39 @@ function defineKnowledgeCatalog(documents, options = {}) {
|
|
|
68
69
|
...(0, catalog_js_1.readonlyCatalog)([...catalog.values()].map((entry) => entry.document), (id) => new TypeError(`Unknown knowledge document: ${id}`)),
|
|
69
70
|
sectionIds,
|
|
70
71
|
assertSelection,
|
|
71
|
-
read(input) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
72
|
+
read(input, context = {}) {
|
|
73
|
+
return (0, native_sub_flow_js_1.nativeSubFlowSync)(context, 'knowledge', input.documentId, () => {
|
|
74
|
+
const { read, entry } = resolve(input), raw = read.selection;
|
|
75
|
+
const selection = raw.mode === 'document'
|
|
76
|
+
? Object.freeze({ mode: 'document' })
|
|
77
|
+
: Object.freeze({ mode: raw.mode, sectionIds: Object.freeze([...raw.sectionIds]) });
|
|
78
|
+
const content = (selection.mode === 'document'
|
|
79
|
+
? (0, sections_js_1.knowledgeText)(entry.document.parts)
|
|
80
|
+
: selection.sectionIds
|
|
81
|
+
.map((id) => (0, sections_js_1.knowledgeText)(entry.sections.get(id).parts, selection.mode === 'subtree'))
|
|
82
|
+
.join('\n\n')).trim();
|
|
83
|
+
if (maxChars !== undefined && content.length > maxChars)
|
|
84
|
+
throw new RangeError('Knowledge selection exceeds its budget');
|
|
85
|
+
// Preserve the existing opaque snapshot identity format.
|
|
86
|
+
const identitySelection = selection.mode === 'document'
|
|
87
|
+
? selection
|
|
88
|
+
: { mode: selection.mode, sections: selection.sectionIds };
|
|
89
|
+
const snapshot = Object.freeze({
|
|
90
|
+
documentId: read.documentId,
|
|
91
|
+
selection,
|
|
92
|
+
revision: entry.document.revision,
|
|
93
|
+
locale: entry.document.locale,
|
|
94
|
+
content,
|
|
95
|
+
id: JSON.stringify([
|
|
96
|
+
read.documentId,
|
|
97
|
+
entry.document.revision,
|
|
98
|
+
entry.document.locale,
|
|
99
|
+
identitySelection,
|
|
100
|
+
]),
|
|
101
|
+
});
|
|
102
|
+
(0, observer_js_1.observeSafely)(observe, snapshot);
|
|
103
|
+
return snapshot;
|
|
99
104
|
});
|
|
100
|
-
(0, observer_js_1.observeSafely)(observe, snapshot);
|
|
101
|
-
return snapshot;
|
|
102
105
|
},
|
|
103
106
|
});
|
|
104
107
|
}
|
|
@@ -12,6 +12,7 @@ exports.defineRecoveryChain = defineRecoveryChain;
|
|
|
12
12
|
*
|
|
13
13
|
* Exports: `definePolicySet`, `defineRecoveryChain`, `Policies`, and the policy types.
|
|
14
14
|
*/
|
|
15
|
+
const native_sub_flow_js_1 = require("../diagnostics/native-sub-flow.js");
|
|
15
16
|
const catalog_js_1 = require("../utils/catalog.js");
|
|
16
17
|
const synchronous_js_1 = require("../utils/synchronous.js");
|
|
17
18
|
const rules_js_1 = require("../utils/rules.js");
|
|
@@ -70,9 +71,9 @@ function defineRecoveryChain(definitions) {
|
|
|
70
71
|
},
|
|
71
72
|
});
|
|
72
73
|
});
|
|
73
|
-
const tryRecover = (input) => {
|
|
74
|
+
const tryRecover = (input, execution = {}) => {
|
|
74
75
|
for (const policy of catalog) {
|
|
75
|
-
const result = policy.tryRecover(input);
|
|
76
|
+
const result = (0, native_sub_flow_js_1.nativeSubFlowSync)(execution, 'recovery', policy.id, () => policy.tryRecover(input));
|
|
76
77
|
if (result.handled)
|
|
77
78
|
return result;
|
|
78
79
|
}
|
|
@@ -10,6 +10,7 @@ exports.defineOutputCatalog = defineOutputCatalog;
|
|
|
10
10
|
*
|
|
11
11
|
* Exports: `defineOutputCatalog`, and the output definition/field/provider/result types.
|
|
12
12
|
*/
|
|
13
|
+
const native_sub_flow_js_1 = require("../../diagnostics/native-sub-flow.js");
|
|
13
14
|
const schema_adapter_js_1 = require("../../utils/schema-adapter.js");
|
|
14
15
|
const catalog_js_1 = require("../../utils/catalog.js");
|
|
15
16
|
const synchronous_js_1 = require("../../utils/synchronous.js");
|
|
@@ -324,7 +325,7 @@ function defineOutputCatalog(definitions, options = {}) {
|
|
|
324
325
|
throw new TypeError('Use a named output request');
|
|
325
326
|
if (!context?.signal)
|
|
326
327
|
throw new TypeError('Output composition requires OperationContext');
|
|
327
|
-
return composeInternal(request.outputId, request.input, context);
|
|
328
|
+
return (0, native_sub_flow_js_1.nativeSubFlowSync)(context, 'output', request.outputId, () => composeInternal(request.outputId, request.input, context));
|
|
328
329
|
},
|
|
329
330
|
});
|
|
330
331
|
}
|
|
@@ -12,6 +12,7 @@ exports.defineRetrieval = defineRetrieval;
|
|
|
12
12
|
*
|
|
13
13
|
* Exports: `defineRetrieval`, `retrievalQueryKey`, `Retrieval`, and the retrieval port types.
|
|
14
14
|
*/
|
|
15
|
+
const native_sub_flow_js_1 = require("../diagnostics/native-sub-flow.js");
|
|
15
16
|
const synchronous_js_1 = require("../utils/synchronous.js");
|
|
16
17
|
const query_key_js_1 = require("../utils/query-key.js");
|
|
17
18
|
const rules_js_1 = require("../utils/rules.js");
|
|
@@ -148,7 +149,12 @@ function defineRetrieval(definition) {
|
|
|
148
149
|
}
|
|
149
150
|
return receipt;
|
|
150
151
|
}
|
|
151
|
-
return Object.freeze({
|
|
152
|
+
return Object.freeze({
|
|
153
|
+
id,
|
|
154
|
+
description,
|
|
155
|
+
effects,
|
|
156
|
+
run: (input, context) => (0, native_sub_flow_js_1.nativeSubFlowSync)(context, 'retrieval', id, () => run(input, context)),
|
|
157
|
+
});
|
|
152
158
|
}
|
|
153
159
|
function reason(value, query, context) {
|
|
154
160
|
return () => (typeof value === 'function' ? value(query, context) : value);
|
package/dist/cjs/kits/tools.js
CHANGED
|
@@ -92,6 +92,7 @@ class ToolLifecycleRegistry {
|
|
|
92
92
|
});
|
|
93
93
|
this.diagnostics = this.options.execution?.diagnostics;
|
|
94
94
|
this.invocationPorts = Object.freeze({
|
|
95
|
+
logger: this.options.logger,
|
|
95
96
|
diagnostics: this.options.diagnostics ?? (() => this.diagnostics),
|
|
96
97
|
signal: this.options.signal,
|
|
97
98
|
journal: this.options.journal,
|
|
@@ -10,6 +10,7 @@ exports.retryMultipleModelCalls = retryMultipleModelCalls;
|
|
|
10
10
|
*
|
|
11
11
|
* Exports: `retryMultipleModelCalls`.
|
|
12
12
|
*/
|
|
13
|
+
const native_sub_flow_js_1 = require("../diagnostics/native-sub-flow.js");
|
|
13
14
|
const errors_js_1 = require("../errors.js");
|
|
14
15
|
/**
|
|
15
16
|
* Retry once when the failure is a rejected multi-call proposal.
|
|
@@ -28,6 +29,6 @@ async function retryMultipleModelCalls(request) {
|
|
|
28
29
|
catch (error) {
|
|
29
30
|
if (!(0, errors_js_1.getErrorInfo)(error).codes.includes('MODEL_MULTIPLE_CALLS'))
|
|
30
31
|
throw error;
|
|
31
|
-
return request.retry(error);
|
|
32
|
+
return (0, native_sub_flow_js_1.nativeSubFlowAsync)(request, 'retry', 'MODEL_MULTIPLE_CALLS', () => request.retry(error));
|
|
32
33
|
}
|
|
33
34
|
}
|
package/dist/cjs/model/runner.js
CHANGED
|
@@ -13,6 +13,8 @@ exports.ModelRunner = exports.BudgetError = void 0;
|
|
|
13
13
|
* Exports: `ModelRunner`, the re-exported `BudgetError`, and the runtime/config type
|
|
14
14
|
* re-exports at the bottom of the file.
|
|
15
15
|
*/
|
|
16
|
+
const sub_flow_js_1 = require("../diagnostics/sub-flow.js");
|
|
17
|
+
const native_sub_flow_js_1 = require("../diagnostics/native-sub-flow.js");
|
|
16
18
|
const events_js_1 = require("../execution/events.js");
|
|
17
19
|
const call_budget_js_1 = require("./call-budget.js");
|
|
18
20
|
const synchronous_js_1 = require("../utils/synchronous.js");
|
|
@@ -321,6 +323,19 @@ class ModelRunner {
|
|
|
321
323
|
return snapshot;
|
|
322
324
|
}
|
|
323
325
|
async invoke(request) {
|
|
326
|
+
const context = typeof request === 'string' ? { logger: undefined, signal: undefined } : request;
|
|
327
|
+
(0, sub_flow_js_1.requireSubFlowLogger)(context.logger);
|
|
328
|
+
const callId = (0, invocation_js_1.invocationId)();
|
|
329
|
+
return (0, native_sub_flow_js_1.nativeSubFlowAsync)({
|
|
330
|
+
logger: context.logger,
|
|
331
|
+
signal: (0, cancellation_js_1.combineSignals)(this.signal, context.signal),
|
|
332
|
+
invocationId: callId,
|
|
333
|
+
}, 'model', typeof request === 'string'
|
|
334
|
+
? defaults_js_1.modelRunnerDefaults.stage
|
|
335
|
+
: (request.stageId ?? request.prepared?.stageId ?? defaults_js_1.modelRunnerDefaults.stage), () => this.invokeRequest(request, callId));
|
|
336
|
+
}
|
|
337
|
+
/** Validate and execute a single request; optional recording is owned by invoke. */
|
|
338
|
+
async invokeRequest(request, callId) {
|
|
324
339
|
const call = typeof request === 'string' ? { input: request } : request;
|
|
325
340
|
const state = call.prepared === undefined ? undefined : this.preparedCalls.get(call.prepared);
|
|
326
341
|
if (call.prepared !== undefined && (!state || state.used))
|
|
@@ -384,7 +399,7 @@ class ModelRunner {
|
|
|
384
399
|
throw invalid('Prepared model request settings cannot be replaced');
|
|
385
400
|
if (state)
|
|
386
401
|
state.used = true;
|
|
387
|
-
return this.invokePrepared(stage, input, tokens, transportId, call.diagnostics, prepared, call.signal);
|
|
402
|
+
return this.invokePrepared(stage, input, tokens, transportId, call.diagnostics, prepared, call.signal, callId);
|
|
388
403
|
}
|
|
389
404
|
/**
|
|
390
405
|
* Acquire the per-runner call slot and execute one call.
|
|
@@ -403,7 +418,7 @@ class ModelRunner {
|
|
|
403
418
|
* @returns The parsed result with invocation metadata.
|
|
404
419
|
* @throws Error When a call is already in flight or the request capacity is exhausted.
|
|
405
420
|
*/
|
|
406
|
-
async invokePrepared(stage, input, tokens, transportId, diagnostics = this.ports.diagnostics, prepared, requestSignal) {
|
|
421
|
+
async invokePrepared(stage, input, tokens, transportId, diagnostics = this.ports.diagnostics, prepared, requestSignal, callId = (0, invocation_js_1.invocationId)()) {
|
|
407
422
|
const configuredRun = this.ports.diagnostics?.identity?.runId, selectedRun = diagnostics?.identity?.runId;
|
|
408
423
|
if (configuredRun && selectedRun && configuredRun !== selectedRun)
|
|
409
424
|
throw (0, errors_js_1.recordErrorContext)(new TypeError('Model observation parent belongs to a different run'), { stageId: stage, codes: ['MODEL_CONFIG'], isRetryable: false });
|
|
@@ -413,7 +428,7 @@ class ModelRunner {
|
|
|
413
428
|
this.requestGate.active++;
|
|
414
429
|
let failure;
|
|
415
430
|
try {
|
|
416
|
-
return await this.execute(stage, input, tokens, transportId, (0, cancellation_js_1.combineSignals)(this.signal, requestSignal), diagnostics, prepared);
|
|
431
|
+
return await this.execute(stage, input, tokens, transportId, (0, cancellation_js_1.combineSignals)(this.signal, requestSignal), diagnostics, prepared, callId);
|
|
417
432
|
}
|
|
418
433
|
catch (error) {
|
|
419
434
|
failure = (0, errors_js_1.recordErrorContext)(error, { stageId: stage });
|
|
@@ -444,8 +459,8 @@ class ModelRunner {
|
|
|
444
459
|
* @returns The parsed result with invocation metadata.
|
|
445
460
|
* @throws Error or ValidationError from any phase, decorated with stage context.
|
|
446
461
|
*/
|
|
447
|
-
async execute(stage, input, tokens, transportId, signal, parentDiagnostics = this.ports.diagnostics, prepared) {
|
|
448
|
-
const id =
|
|
462
|
+
async execute(stage, input, tokens, transportId, signal, parentDiagnostics = this.ports.diagnostics, prepared, callId = (0, invocation_js_1.invocationId)()) {
|
|
463
|
+
const id = callId, startedAtMs = Date.now();
|
|
449
464
|
this.activeCall = undefined;
|
|
450
465
|
const invocationDiagnostics = parentDiagnostics?.child(id, {
|
|
451
466
|
invocationId: id,
|
|
@@ -14,6 +14,7 @@ exports.createContextReductionNode = createContextReductionNode;
|
|
|
14
14
|
* Main exports: `createContextProcessingNode`, `createContextSelectionNode`,
|
|
15
15
|
* `createContextReductionNode` and their result/definition types.
|
|
16
16
|
*/
|
|
17
|
+
const native_sub_flow_js_1 = require("../../diagnostics/native-sub-flow.js");
|
|
17
18
|
const processing_js_1 = require("./processing.js");
|
|
18
19
|
const defaults_js_1 = require("../../model/defaults.js");
|
|
19
20
|
const synchronous_js_1 = require("../../utils/synchronous.js");
|
|
@@ -129,53 +130,55 @@ function contextNode(definition, execute) {
|
|
|
129
130
|
onErrorRouteId: definition.onErrorRouteId,
|
|
130
131
|
routes: definition.routes,
|
|
131
132
|
async run(state, context) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
diagnostics: context.diagnostics,
|
|
154
|
-
compressors,
|
|
155
|
-
selectors,
|
|
156
|
-
// Read lazily so handlers see the live budget rather than the value at preparation.
|
|
157
|
-
remainingCalls: () => prepared.remainingCalls,
|
|
158
|
-
callModel: (options) => context.model.invoke({
|
|
159
|
-
...options,
|
|
160
|
-
modelId: options.modelId ?? prepared.modelId,
|
|
133
|
+
return (0, native_sub_flow_js_1.nativeSubFlowAsync)(context, 'context', definition.id, async () => {
|
|
134
|
+
// The node timeout is an additional bound; parent cancellation still wins.
|
|
135
|
+
const signal = (0, cancellation_js_1.combineSignals)(context.signal, AbortSignal.timeout(timeoutMs));
|
|
136
|
+
const prepared = selectPrepared
|
|
137
|
+
? selectPrepared(state, context)
|
|
138
|
+
: context.model.prepare(typeof request === 'function' ? request(state, context) : request);
|
|
139
|
+
const input = (0, synchronous_js_1.synchronous)(plan(state, context), 'Context plans must be synchronous');
|
|
140
|
+
// An empty measurement reports the allowance left after transport, instruction and schema
|
|
141
|
+
// overhead, so processing must fit inside whichever limit is tighter.
|
|
142
|
+
const overhead = prepared.measure([]);
|
|
143
|
+
const fullLimit = Math.min(input.maxInputChars, overhead.maxInputChars);
|
|
144
|
+
const bodyLimit = fullLimit;
|
|
145
|
+
(0, rules_js_1.breakWhile)(bodyLimit < 1, 'No input capacity for context');
|
|
146
|
+
const work = (0, processing_js_1.beginContextProcessing)({
|
|
147
|
+
fragments: input.fragments,
|
|
148
|
+
additionalMessages: input.additionalMessages,
|
|
149
|
+
originalFragments: input.originalFragments,
|
|
150
|
+
mutableFragmentIds: input.mutableFragmentIds,
|
|
151
|
+
maxInputChars: bodyLimit,
|
|
152
|
+
}, policy, {
|
|
153
|
+
stageId: prepared.stageId,
|
|
161
154
|
signal,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
155
|
+
diagnostics: context.diagnostics,
|
|
156
|
+
compressors,
|
|
157
|
+
selectors,
|
|
158
|
+
// Read lazily so handlers see the live budget rather than the value at preparation.
|
|
159
|
+
remainingCalls: () => prepared.remainingCalls,
|
|
160
|
+
callModel: (options) => context.model.invoke({
|
|
161
|
+
...options,
|
|
162
|
+
modelId: options.modelId ?? prepared.modelId,
|
|
163
|
+
signal,
|
|
164
|
+
}),
|
|
165
|
+
...(overhead.counterId
|
|
166
|
+
? {
|
|
167
|
+
tokenBudget: {
|
|
168
|
+
counterId: overhead.counterId,
|
|
169
|
+
inputLimit: overhead.inputTokenLimit,
|
|
170
|
+
measure: (messages) => prepared.measure(messages).inputTokens,
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
: {}),
|
|
174
|
+
});
|
|
175
|
+
context.report({ payload: { phase: 'processing', fragmentCount: input.fragments.length } });
|
|
176
|
+
const result = await execute(work, prepared, fullLimit, state, context);
|
|
177
|
+
// Never report or commit a result produced after cancellation.
|
|
178
|
+
signal.throwIfAborted();
|
|
179
|
+
context.report({ payload: { phase: 'processed', report: work.report } });
|
|
180
|
+
return (0, synchronous_js_1.synchronous)(update(result, state), 'Context node updates must be synchronous');
|
|
172
181
|
});
|
|
173
|
-
context.report({ payload: { phase: 'processing', fragmentCount: input.fragments.length } });
|
|
174
|
-
const result = await execute(work, prepared, fullLimit, state, context);
|
|
175
|
-
// Never report or commit a result produced after cancellation.
|
|
176
|
-
signal.throwIfAborted();
|
|
177
|
-
context.report({ payload: { phase: 'processed', report: work.report } });
|
|
178
|
-
return (0, synchronous_js_1.synchronous)(update(result, state), 'Context node updates must be synchronous');
|
|
179
182
|
},
|
|
180
183
|
};
|
|
181
184
|
}
|
|
@@ -26,6 +26,7 @@ exports.processContext = processContext;
|
|
|
26
26
|
* `finishContextProcessing` (staged runs), the policy/reduction catalogs and the individual
|
|
27
27
|
* validation, measurement and reduction helpers used by workflow nodes.
|
|
28
28
|
*/
|
|
29
|
+
const native_sub_flow_js_1 = require("../../diagnostics/native-sub-flow.js");
|
|
29
30
|
const snapshot_js_1 = require("./snapshot.js");
|
|
30
31
|
const audit_js_1 = require("../../context/audit.js");
|
|
31
32
|
const history_js_1 = require("./history.js");
|
|
@@ -610,7 +611,9 @@ function finishContextProcessing(state) {
|
|
|
610
611
|
* @throws {BudgetError} When a handler exhausts its call allowance.
|
|
611
612
|
*/
|
|
612
613
|
async function processContext(plan, policy, ports) {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
614
|
+
return (0, native_sub_flow_js_1.nativeSubFlowAsync)(ports, 'context', policy.mode, async () => {
|
|
615
|
+
const state = beginContextProcessing(plan, policy, ports);
|
|
616
|
+
await exports.contextPolicyCatalog[policy.mode].run(state);
|
|
617
|
+
return finishContextProcessing(state);
|
|
618
|
+
});
|
|
616
619
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Exports: `executeInvocation` and the invocation contracts re-exported at the bottom.
|
|
10
10
|
*/
|
|
11
|
+
import { nativeSubFlowSync } from '../diagnostics/native-sub-flow.js';
|
|
11
12
|
import { invocationId } from '../utils/invocation.js';
|
|
12
13
|
import { synchronous } from '../utils/synchronous.js';
|
|
13
14
|
import { diagnosticError } from '../diagnostics/index.js';
|
|
@@ -28,12 +29,30 @@ import { NodeReports } from '../execution/reporting.js';
|
|
|
28
29
|
* signal checks.
|
|
29
30
|
*/
|
|
30
31
|
export function executeInvocation(invocation, input, context, ports = {}) {
|
|
32
|
+
let logger;
|
|
33
|
+
try {
|
|
34
|
+
logger = ports.logger?.(context);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* Optional recording cannot block execution. */
|
|
38
|
+
}
|
|
39
|
+
const callId = invocationId();
|
|
40
|
+
return nativeSubFlowSync({
|
|
41
|
+
logger,
|
|
42
|
+
invocationId: callId,
|
|
43
|
+
get signal() {
|
|
44
|
+
return ports.signal?.(context);
|
|
45
|
+
},
|
|
46
|
+
}, 'invocation', invocation.id, (scopedLogger) => runInvocation(invocation, input, context, ports, scopedLogger, callId));
|
|
47
|
+
}
|
|
48
|
+
/** Execute the existing synchronous lifecycle without changing journal or error precedence. */
|
|
49
|
+
function runInvocation(invocation, input, context, ports, logger, executionId = invocationId()) {
|
|
31
50
|
const toolId = invocation.id;
|
|
32
51
|
// Identify the call before touching the ports: journal and diagnostics records cannot be
|
|
33
52
|
// reconciled with an anonymous handler.
|
|
34
53
|
if (!toolId?.trim())
|
|
35
54
|
throw new TypeError('Invalid invocation handler identity');
|
|
36
|
-
const journal = ports.journal?.(context), id =
|
|
55
|
+
const journal = ports.journal?.(context), id = executionId, startedAtMs = Date.now();
|
|
37
56
|
const diagnostics = ports.diagnostics?.(context)?.child(id, {
|
|
38
57
|
invocationId: id,
|
|
39
58
|
nodeRole: 'invocation',
|
|
@@ -64,6 +83,7 @@ export function executeInvocation(invocation, input, context, ports = {}) {
|
|
|
64
83
|
// The helper rejects a promise and drains its rejection: a handler that turns async must
|
|
65
84
|
// fail here instead of escaping as an unhandled rejection.
|
|
66
85
|
synchronous(invocation.call(input, context, {
|
|
86
|
+
logger,
|
|
67
87
|
mode: 'sync',
|
|
68
88
|
invocationId: id,
|
|
69
89
|
signal: signal ?? new AbortController().signal,
|
|
@@ -27,7 +27,14 @@ function execute(definition, input, context, execution) {
|
|
|
27
27
|
signal.throwIfAborted();
|
|
28
28
|
return value;
|
|
29
29
|
};
|
|
30
|
-
const operation = {
|
|
30
|
+
const operation = {
|
|
31
|
+
app: context,
|
|
32
|
+
signal,
|
|
33
|
+
diagnostics,
|
|
34
|
+
logger: execution.logger,
|
|
35
|
+
report,
|
|
36
|
+
createSubFlowLogger,
|
|
37
|
+
};
|
|
31
38
|
const authorized = (result) => {
|
|
32
39
|
assertion(result, 'Tool authorization must return void');
|
|
33
40
|
signal.throwIfAborted();
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Exports: `ToolRegistry`, `executeInvocation`, and the tool/invocation contracts.
|
|
13
13
|
*/
|
|
14
|
+
import { nativeSubFlowSync, nativeSubFlowAsync } from '../diagnostics/native-sub-flow.js';
|
|
14
15
|
import { executionEvents } from '../execution/events.js';
|
|
15
16
|
import { invocationId as nextInvocationId, invocationResult, toolInvocation, } from '../utils/invocation.js';
|
|
16
17
|
import { synchronous } from '../utils/synchronous.js';
|
|
@@ -116,7 +117,8 @@ export class ToolRegistry {
|
|
|
116
117
|
*/
|
|
117
118
|
invoke(request) {
|
|
118
119
|
const call = toolInvocation(request, arguments.length);
|
|
119
|
-
|
|
120
|
+
const callId = nextInvocationId();
|
|
121
|
+
return nativeSubFlowSync({ ...call, signal: combineSignals(this.ports.signal, call.signal), invocationId: callId }, 'tool', call.toolId, (scopedLogger) => this.execute(call.toolId, call.input, false, call.diagnostics, call.signal, scopedLogger, callId));
|
|
120
122
|
}
|
|
121
123
|
/**
|
|
122
124
|
* Invoke a registered tool and await its result.
|
|
@@ -128,7 +130,8 @@ export class ToolRegistry {
|
|
|
128
130
|
*/
|
|
129
131
|
async invokeAsync(request) {
|
|
130
132
|
const call = toolInvocation(request, arguments.length);
|
|
131
|
-
|
|
133
|
+
const callId = nextInvocationId();
|
|
134
|
+
return nativeSubFlowAsync({ ...call, signal: combineSignals(this.ports.signal, call.signal), invocationId: callId }, 'tool', call.toolId, (scopedLogger) => this.execute(call.toolId, call.input, true, call.diagnostics, call.signal, scopedLogger, callId));
|
|
132
135
|
}
|
|
133
136
|
/**
|
|
134
137
|
* Run one call: validate, parse input, execute, parse output, then record the outcome.
|
|
@@ -140,7 +143,7 @@ export class ToolRegistry {
|
|
|
140
143
|
* @param requestSignal Per-call signal, combined with the request-lifetime signal.
|
|
141
144
|
* @returns The frozen result on success; every failure path throws.
|
|
142
145
|
*/
|
|
143
|
-
execute(name, input, asynchronous, parentDiagnostics = this.diagnostics, requestSignal) {
|
|
146
|
+
execute(name, input, asynchronous, parentDiagnostics = this.diagnostics, requestSignal, logger, callId = nextInvocationId()) {
|
|
144
147
|
// A tool call stays inside the run that invoked it: mixing two diagnostic trees would
|
|
145
148
|
// produce records with two parents and break run-scoped correlation.
|
|
146
149
|
if (this.diagnostics?.identity?.runId &&
|
|
@@ -152,7 +155,7 @@ export class ToolRegistry {
|
|
|
152
155
|
throw this.ports.unavailable?.(name) ?? new Error(`Tool is not registered: ${name}`);
|
|
153
156
|
// Either signal may cancel the call; combining them keeps both lifetimes effective.
|
|
154
157
|
const signal = combineSignals(this.ports.signal, requestSignal);
|
|
155
|
-
const invocationId =
|
|
158
|
+
const invocationId = callId;
|
|
156
159
|
const diagnostics = parentDiagnostics?.child(invocationId, {
|
|
157
160
|
invocationId,
|
|
158
161
|
nodeRole: 'invocation',
|
|
@@ -190,24 +193,15 @@ export class ToolRegistry {
|
|
|
190
193
|
};
|
|
191
194
|
const succeed = (result) => {
|
|
192
195
|
signal.throwIfAborted();
|
|
193
|
-
let debug = reports.debug();
|
|
194
196
|
if (tool.debugSteps && diagnostics?.enabled('tool.result', 'content')) {
|
|
195
197
|
try {
|
|
196
|
-
debug
|
|
197
|
-
subs: synchronous(tool.debugSteps(result, reporting), 'Tool debug reports must be synchronous'),
|
|
198
|
-
});
|
|
198
|
+
synchronous(tool.debugSteps(result, reporting), 'Tool debug reports must be synchronous');
|
|
199
199
|
}
|
|
200
|
-
catch
|
|
201
|
-
|
|
202
|
-
// a failure. Defer the error until a consumer actually asks for the sub-steps.
|
|
203
|
-
debug = {
|
|
204
|
-
usedModel: reports.debug().usedModel,
|
|
205
|
-
subSteps: () => {
|
|
206
|
-
throw error;
|
|
207
|
-
},
|
|
208
|
-
};
|
|
200
|
+
catch {
|
|
201
|
+
diagnostics?.emit('node.progress', () => ({ reportError: 'INVALID_NODE_REPORT' }));
|
|
209
202
|
}
|
|
210
203
|
}
|
|
204
|
+
const debug = reports.debug();
|
|
211
205
|
signal.throwIfAborted();
|
|
212
206
|
reports.close();
|
|
213
207
|
diagnostics?.emit('tool.result', () => ({
|
|
@@ -277,6 +271,7 @@ export class ToolRegistry {
|
|
|
277
271
|
signal.throwIfAborted();
|
|
278
272
|
phase = 'execute';
|
|
279
273
|
const value = tool.execute(parsed, {
|
|
274
|
+
logger,
|
|
280
275
|
mode: asynchronous ? 'async' : 'sync',
|
|
281
276
|
invocationId,
|
|
282
277
|
signal,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DiagnosticContext, CreateDiagnosticsOptions } from '../structs/diagnostics.js';
|
|
2
2
|
export * from '../structs/diagnostics.js';
|
|
3
3
|
export * from './catalog.js';
|
|
4
|
+
export { SubFlowLogger, ScopedSubFlowLogger } from './sub-flow.js';
|
|
4
5
|
export type * from '../structs/debug.js';
|
|
5
6
|
export { reportedStepStatusCatalog, reportedStepStatuses } from '../structs/debug.js';
|
|
6
7
|
/**
|