@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.
Files changed (97) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +28 -26
  3. package/development/docs/api/README.en.md +2 -0
  4. package/development/docs/api/README.md +2 -0
  5. package/development/docs/api/observability.en.md +37 -11
  6. package/development/docs/api/observability.md +64 -11
  7. package/development/docs/api/reference.en.md +469 -348
  8. package/development/docs/api/reference.md +193 -137
  9. package/development/docs/api/types.en.md +1 -0
  10. package/development/docs/api/types.md +1 -0
  11. package/development/docs/api/workflow-views.en.md +64 -0
  12. package/development/docs/api/workflow-views.md +78 -0
  13. package/development/docs/api/workflow.en.md +6 -2
  14. package/development/docs/api/workflow.md +6 -2
  15. package/development/skills/agent-core-app/SKILL.md +12 -0
  16. package/dist/cjs/capabilities/invocation.js +21 -1
  17. package/dist/cjs/capabilities/tool-runtime.js +8 -1
  18. package/dist/cjs/capabilities/tools.js +12 -17
  19. package/dist/cjs/diagnostics/index.js +51 -3
  20. package/dist/cjs/diagnostics/native-sub-flow.js +106 -0
  21. package/dist/cjs/diagnostics/sub-flow.js +278 -32
  22. package/dist/cjs/execution/engine.js +3 -2
  23. package/dist/cjs/execution/events.js +5 -5
  24. package/dist/cjs/execution/reporting.js +18 -28
  25. package/dist/cjs/execution/workflow-chain.js +211 -0
  26. package/dist/cjs/execution/workflow-graph.js +72 -0
  27. package/dist/cjs/execution/workflow.js +34 -6
  28. package/dist/cjs/kits/aggregation.js +17 -14
  29. package/dist/cjs/kits/answering/checks.js +2 -1
  30. package/dist/cjs/kits/answering/flow.js +24 -21
  31. package/dist/cjs/kits/answering/tasks.js +25 -20
  32. package/dist/cjs/kits/delivery.js +36 -24
  33. package/dist/cjs/kits/knowledge/catalog.js +33 -30
  34. package/dist/cjs/kits/policies.js +3 -2
  35. package/dist/cjs/kits/presentation/outputs.js +2 -1
  36. package/dist/cjs/kits/retrieval.js +7 -1
  37. package/dist/cjs/kits/tools.js +1 -0
  38. package/dist/cjs/model/decision-retry.js +2 -1
  39. package/dist/cjs/model/runner.js +20 -5
  40. package/dist/cjs/structs/execution/workflow-views.js +2 -0
  41. package/dist/cjs/support/context/nodes.js +48 -45
  42. package/dist/cjs/support/context/processing.js +6 -3
  43. package/dist/cjs/utils/invocation.js +1 -0
  44. package/dist/esm/capabilities/invocation.js +21 -1
  45. package/dist/esm/capabilities/tool-runtime.js +8 -1
  46. package/dist/esm/capabilities/tools.js +12 -17
  47. package/dist/esm/diagnostics/index.d.ts +1 -0
  48. package/dist/esm/diagnostics/index.js +48 -2
  49. package/dist/esm/diagnostics/native-sub-flow.d.ts +94 -0
  50. package/dist/esm/diagnostics/native-sub-flow.js +101 -0
  51. package/dist/esm/diagnostics/sub-flow.d.ts +56 -4
  52. package/dist/esm/diagnostics/sub-flow.js +271 -32
  53. package/dist/esm/execution/engine.d.ts +1 -0
  54. package/dist/esm/execution/engine.js +3 -2
  55. package/dist/esm/execution/events.js +5 -5
  56. package/dist/esm/execution/reporting.d.ts +6 -12
  57. package/dist/esm/execution/reporting.js +19 -29
  58. package/dist/esm/execution/workflow-chain.d.ts +3 -0
  59. package/dist/esm/execution/workflow-chain.js +208 -0
  60. package/dist/esm/execution/workflow-graph.d.ts +7 -0
  61. package/dist/esm/execution/workflow-graph.js +68 -0
  62. package/dist/esm/execution/workflow.d.ts +6 -0
  63. package/dist/esm/execution/workflow.js +34 -6
  64. package/dist/esm/kits/aggregation.d.ts +1 -1
  65. package/dist/esm/kits/aggregation.js +17 -14
  66. package/dist/esm/kits/answering/checks.js +2 -1
  67. package/dist/esm/kits/answering/flow.js +24 -21
  68. package/dist/esm/kits/answering/tasks.js +25 -20
  69. package/dist/esm/kits/delivery.d.ts +0 -9
  70. package/dist/esm/kits/delivery.js +36 -24
  71. package/dist/esm/kits/knowledge/catalog.js +33 -30
  72. package/dist/esm/kits/policies.d.ts +1 -1
  73. package/dist/esm/kits/policies.js +3 -2
  74. package/dist/esm/kits/presentation/outputs.js +2 -1
  75. package/dist/esm/kits/retrieval.js +7 -1
  76. package/dist/esm/kits/tools.js +1 -0
  77. package/dist/esm/model/decision-retry.d.ts +2 -0
  78. package/dist/esm/model/decision-retry.js +2 -1
  79. package/dist/esm/model/runner.d.ts +2 -0
  80. package/dist/esm/model/runner.js +20 -5
  81. package/dist/esm/structs/capabilities/invocation.d.ts +2 -0
  82. package/dist/esm/structs/capabilities/tools.d.ts +7 -3
  83. package/dist/esm/structs/common.d.ts +2 -0
  84. package/dist/esm/structs/debug.d.ts +36 -20
  85. package/dist/esm/structs/execution/workflow-views.d.ts +123 -0
  86. package/dist/esm/structs/execution/workflow-views.js +1 -0
  87. package/dist/esm/structs/execution/workflow.d.ts +4 -3
  88. package/dist/esm/structs/index.d.ts +1 -0
  89. package/dist/esm/structs/model/runtime.d.ts +2 -0
  90. package/dist/esm/support/context/nodes.js +48 -45
  91. package/dist/esm/support/context/processing.js +6 -3
  92. package/dist/esm/utils/invocation.d.ts +1 -0
  93. package/dist/esm/utils/invocation.js +1 -0
  94. package/package.json +1 -1
  95. package/dist/cjs/utils/debug.js +0 -30
  96. package/dist/esm/utils/debug.d.ts +0 -27
  97. package/dist/esm/utils/debug.js +0 -27
@@ -1,3 +1,4 @@
1
+ import type { WorkflowChainSource } from './workflow-views.js';
1
2
  /**
2
3
  * Workflow contract: a state graph whose nodes report their own use of model and tools.
3
4
  *
@@ -66,8 +67,6 @@ export interface WorkflowNodeReport {
66
67
  readonly usedModel?: boolean;
67
68
  /** App-defined progress detail; collected only when content logging is enabled. */
68
69
  readonly payload?: unknown;
69
- /** Logger owned by this visit, used to report sub-steps. */
70
- readonly subs?: import('../debug.js').SubFlowLogger;
71
70
  }
72
71
  /** One node of the graph. */
73
72
  export type WorkflowNode<State, Result, Runtime = undefined> = {
@@ -94,7 +93,7 @@ export type WorkflowNode<State, Result, Runtime = undefined> = {
94
93
  readonly requires?: readonly (keyof State & string)[];
95
94
  /** State keys this node is expected to produce; validated after `run`. */
96
95
  readonly provides?: readonly (keyof State & string)[];
97
- /** Candidate successors, evaluated in order. */
96
+ /** Candidate successors, evaluated in order. A getter must be pure; registration reads it once. */
98
97
  readonly routes: readonly WorkflowRoute<State, Result, Runtime>[];
99
98
  /** Return only changed fields. Core commits them after cancellation and output checks. */
100
99
  readonly run?: (state: Readonly<State>, context: WorkflowContext<Runtime>) => void | Partial<State> | Promise<void | Partial<State>>;
@@ -103,6 +102,8 @@ export type WorkflowNode<State, Result, Runtime = undefined> = {
103
102
  export type AgentWorkflowDefinition<State, Result, Runtime = undefined> = {
104
103
  /** Stable workflow id, also reported in every event. */
105
104
  readonly id: string;
105
+ /** App-owned authorized diagnostic reader; no global run storage is installed. */
106
+ readonly chainSource?: WorkflowChainSource;
106
107
  /** Definition revision; lets hosts distinguish executions of different graph versions. */
107
108
  readonly revision?: string;
108
109
  readonly nodes: readonly WorkflowNode<State, Result, Runtime>[];
@@ -55,3 +55,4 @@ export type * from './invocation.js';
55
55
  export type * from './debug.js';
56
56
  export type * from './execution/events.js';
57
57
  export type * from './execution/cache.js';
58
+ export type * from './execution/workflow-views.js';
@@ -175,6 +175,8 @@ export type ModelRunnerOptions<Transports extends readonly ModelTransportDefinit
175
175
  } & ModelRunnerSettings;
176
176
  /** One model call request. The input shape selects prompt mode or message mode. */
177
177
  export type ModelCallRequest<Transport = string> = {
178
+ /** Record this call in the supplied logger; omission adds no sub-flow record. */
179
+ readonly logger?: import('../debug.js').SubFlowLogger;
178
180
  /** Additional cancellation can shorten, never replace, the Runner lifetime. */
179
181
  readonly signal?: AbortSignal;
180
182
  /** Parent observation scope for this invocation; never changes execution budget or signal. */
@@ -9,6 +9,7 @@
9
9
  * Main exports: `createContextProcessingNode`, `createContextSelectionNode`,
10
10
  * `createContextReductionNode` and their result/definition types.
11
11
  */
12
+ import { nativeSubFlowAsync } from '../../diagnostics/native-sub-flow.js';
12
13
  import { beginContextProcessing, finishContextProcessing, chooseSteps, applyReduction, needsReduction, watermarks, validateReductionTargets, contextPolicyCatalog, validateContextPolicy, } from './processing.js';
13
14
  import { modelRunnerDefaults } from '../../model/defaults.js';
14
15
  import { synchronous } from '../../utils/synchronous.js';
@@ -124,53 +125,55 @@ function contextNode(definition, execute) {
124
125
  onErrorRouteId: definition.onErrorRouteId,
125
126
  routes: definition.routes,
126
127
  async run(state, context) {
127
- // The node timeout is an additional bound; parent cancellation still wins.
128
- const signal = combineSignals(context.signal, AbortSignal.timeout(timeoutMs));
129
- const prepared = selectPrepared
130
- ? selectPrepared(state, context)
131
- : context.model.prepare(typeof request === 'function' ? request(state, context) : request);
132
- const input = synchronous(plan(state, context), 'Context plans must be synchronous');
133
- // An empty measurement reports the allowance left after transport, instruction and schema
134
- // overhead, so processing must fit inside whichever limit is tighter.
135
- const overhead = prepared.measure([]);
136
- const fullLimit = Math.min(input.maxInputChars, overhead.maxInputChars);
137
- const bodyLimit = fullLimit;
138
- breakWhile(bodyLimit < 1, 'No input capacity for context');
139
- const work = beginContextProcessing({
140
- fragments: input.fragments,
141
- additionalMessages: input.additionalMessages,
142
- originalFragments: input.originalFragments,
143
- mutableFragmentIds: input.mutableFragmentIds,
144
- maxInputChars: bodyLimit,
145
- }, policy, {
146
- stageId: prepared.stageId,
147
- signal,
148
- diagnostics: context.diagnostics,
149
- compressors,
150
- selectors,
151
- // Read lazily so handlers see the live budget rather than the value at preparation.
152
- remainingCalls: () => prepared.remainingCalls,
153
- callModel: (options) => context.model.invoke({
154
- ...options,
155
- modelId: options.modelId ?? prepared.modelId,
128
+ return nativeSubFlowAsync(context, 'context', definition.id, async () => {
129
+ // The node timeout is an additional bound; parent cancellation still wins.
130
+ const signal = combineSignals(context.signal, AbortSignal.timeout(timeoutMs));
131
+ const prepared = selectPrepared
132
+ ? selectPrepared(state, context)
133
+ : context.model.prepare(typeof request === 'function' ? request(state, context) : request);
134
+ const input = synchronous(plan(state, context), 'Context plans must be synchronous');
135
+ // An empty measurement reports the allowance left after transport, instruction and schema
136
+ // overhead, so processing must fit inside whichever limit is tighter.
137
+ const overhead = prepared.measure([]);
138
+ const fullLimit = Math.min(input.maxInputChars, overhead.maxInputChars);
139
+ const bodyLimit = fullLimit;
140
+ breakWhile(bodyLimit < 1, 'No input capacity for context');
141
+ const work = beginContextProcessing({
142
+ fragments: input.fragments,
143
+ additionalMessages: input.additionalMessages,
144
+ originalFragments: input.originalFragments,
145
+ mutableFragmentIds: input.mutableFragmentIds,
146
+ maxInputChars: bodyLimit,
147
+ }, policy, {
148
+ stageId: prepared.stageId,
156
149
  signal,
157
- }),
158
- ...(overhead.counterId
159
- ? {
160
- tokenBudget: {
161
- counterId: overhead.counterId,
162
- inputLimit: overhead.inputTokenLimit,
163
- measure: (messages) => prepared.measure(messages).inputTokens,
164
- },
165
- }
166
- : {}),
150
+ diagnostics: context.diagnostics,
151
+ compressors,
152
+ selectors,
153
+ // Read lazily so handlers see the live budget rather than the value at preparation.
154
+ remainingCalls: () => prepared.remainingCalls,
155
+ callModel: (options) => context.model.invoke({
156
+ ...options,
157
+ modelId: options.modelId ?? prepared.modelId,
158
+ signal,
159
+ }),
160
+ ...(overhead.counterId
161
+ ? {
162
+ tokenBudget: {
163
+ counterId: overhead.counterId,
164
+ inputLimit: overhead.inputTokenLimit,
165
+ measure: (messages) => prepared.measure(messages).inputTokens,
166
+ },
167
+ }
168
+ : {}),
169
+ });
170
+ context.report({ payload: { phase: 'processing', fragmentCount: input.fragments.length } });
171
+ const result = await execute(work, prepared, fullLimit, state, context);
172
+ // Never report or commit a result produced after cancellation.
173
+ signal.throwIfAborted();
174
+ context.report({ payload: { phase: 'processed', report: work.report } });
175
+ return synchronous(update(result, state), 'Context node updates must be synchronous');
167
176
  });
168
- context.report({ payload: { phase: 'processing', fragmentCount: input.fragments.length } });
169
- const result = await execute(work, prepared, fullLimit, state, context);
170
- // Never report or commit a result produced after cancellation.
171
- signal.throwIfAborted();
172
- context.report({ payload: { phase: 'processed', report: work.report } });
173
- return synchronous(update(result, state), 'Context node updates must be synchronous');
174
177
  },
175
178
  };
176
179
  }
@@ -11,6 +11,7 @@
11
11
  * `finishContextProcessing` (staged runs), the policy/reduction catalogs and the individual
12
12
  * validation, measurement and reduction helpers used by workflow nodes.
13
13
  */
14
+ import { nativeSubFlowAsync } from '../../diagnostics/native-sub-flow.js';
14
15
  import { snapshotFragment, snapshotMessage } from './snapshot.js';
15
16
  import { auditContextChange as audit } from '../../context/audit.js';
16
17
  import { historyGroups, validateRecentHistory } from './history.js';
@@ -595,7 +596,9 @@ export function finishContextProcessing(state) {
595
596
  * @throws {BudgetError} When a handler exhausts its call allowance.
596
597
  */
597
598
  export async function processContext(plan, policy, ports) {
598
- const state = beginContextProcessing(plan, policy, ports);
599
- await contextPolicyCatalog[policy.mode].run(state);
600
- return finishContextProcessing(state);
599
+ return nativeSubFlowAsync(ports, 'context', policy.mode, async () => {
600
+ const state = beginContextProcessing(plan, policy, ports);
601
+ await contextPolicyCatalog[policy.mode].run(state);
602
+ return finishContextProcessing(state);
603
+ });
601
604
  }
@@ -38,6 +38,7 @@ export declare function invocationResult<Value, Metadata extends InvocationMetad
38
38
  * @throws TypeError When the arity or the request shape is invalid.
39
39
  */
40
40
  export declare function toolInvocation(request: import('../structs/capabilities/tools.js').ToolInvocationRequest, arity: number): {
41
+ logger: import("../index.js").SubFlowLogger | undefined;
41
42
  toolId: string;
42
43
  input: unknown;
43
44
  diagnostics: import("../index.js").DiagnosticContext | undefined;
@@ -41,6 +41,7 @@ export function toolInvocation(request, arity) {
41
41
  throw new TypeError('Use one tool request with toolId and input');
42
42
  }
43
43
  return {
44
+ logger: request.logger,
44
45
  toolId: request.toolId,
45
46
  input: request.input,
46
47
  diagnostics: request.diagnostics,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jangts/agent-core",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "type": "commonjs",
5
5
  "license": "Apache-2.0",
6
6
  "description": "Platform-independent agent runtime and configurable modules for evidence, delivery, policies and interactions",
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.captureSubSteps = captureSubSteps;
4
- const sub_flow_js_1 = require("../diagnostics/sub-flow.js");
5
- const synchronous_js_1 = require("./synchronous.js");
6
- /**
7
- * Read the current sub-step log of one execution visit.
8
- *
9
- * A missing reader or a logger that yields nothing produces the empty shape, which
10
- * lets callers spread the result unconditionally. Failures are reported as one
11
- * dropped step instead of propagating, because diagnostics must not break execution.
12
- *
13
- * @param read - Getter for the current logger; omitted when the caller has no logger.
14
- * @param identity - Diagnostic identity copied onto each captured step.
15
- * @returns Frozen `subSteps`, the number of dropped steps and whether the log was truncated.
16
- */
17
- function captureSubSteps(read, identity) {
18
- const empty = { subSteps: Object.freeze([]), subStepsDropped: 0, subStepsTruncated: false };
19
- if (!read)
20
- return empty;
21
- try {
22
- const logger = (0, synchronous_js_1.synchronous)(read(), 'Debug steps must be synchronous');
23
- return logger === undefined
24
- ? empty
25
- : { ...empty, subSteps: (0, sub_flow_js_1.readSubFlowLogger)(logger, undefined, identity) };
26
- }
27
- catch {
28
- return { ...empty, subStepsDropped: 1 };
29
- }
30
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Adapter between App-supplied debug loggers and the diagnostics pipeline.
3
- *
4
- * Sub-flow loggers are mutable, execution-owned objects. This module reads one at the
5
- * moment a diagnostic fact is built and converts it into a frozen array of steps, so
6
- * persisted observations never retain a live logger.
7
- *
8
- * Exports: `captureSubSteps`.
9
- */
10
- import type { SubFlowLogger } from '../structs/debug.js';
11
- import type { DiagnosticIdentity } from '../structs/diagnostics.js';
12
- /**
13
- * Read the current sub-step log of one execution visit.
14
- *
15
- * A missing reader or a logger that yields nothing produces the empty shape, which
16
- * lets callers spread the result unconditionally. Failures are reported as one
17
- * dropped step instead of propagating, because diagnostics must not break execution.
18
- *
19
- * @param read - Getter for the current logger; omitted when the caller has no logger.
20
- * @param identity - Diagnostic identity copied onto each captured step.
21
- * @returns Frozen `subSteps`, the number of dropped steps and whether the log was truncated.
22
- */
23
- export declare function captureSubSteps(read: (() => SubFlowLogger | undefined) | undefined, identity?: Readonly<DiagnosticIdentity>): {
24
- subSteps: readonly Readonly<import("../index.js").RecordedSubStep>[];
25
- subStepsDropped: number;
26
- subStepsTruncated: boolean;
27
- };
@@ -1,27 +0,0 @@
1
- import { readSubFlowLogger } from '../diagnostics/sub-flow.js';
2
- import { synchronous } from './synchronous.js';
3
- /**
4
- * Read the current sub-step log of one execution visit.
5
- *
6
- * A missing reader or a logger that yields nothing produces the empty shape, which
7
- * lets callers spread the result unconditionally. Failures are reported as one
8
- * dropped step instead of propagating, because diagnostics must not break execution.
9
- *
10
- * @param read - Getter for the current logger; omitted when the caller has no logger.
11
- * @param identity - Diagnostic identity copied onto each captured step.
12
- * @returns Frozen `subSteps`, the number of dropped steps and whether the log was truncated.
13
- */
14
- export function captureSubSteps(read, identity) {
15
- const empty = { subSteps: Object.freeze([]), subStepsDropped: 0, subStepsTruncated: false };
16
- if (!read)
17
- return empty;
18
- try {
19
- const logger = synchronous(read(), 'Debug steps must be synchronous');
20
- return logger === undefined
21
- ? empty
22
- : { ...empty, subSteps: readSubFlowLogger(logger, undefined, identity) };
23
- }
24
- catch {
25
- return { ...empty, subStepsDropped: 1 };
26
- }
27
- }