@jangts/agent-core 0.3.6 → 0.5.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 +20 -0
- package/README.md +5 -5
- package/development/docs/README.en.md +2 -2
- package/development/docs/acceptance.en.md +2 -2
- package/development/docs/agent-development.en.md +1 -1
- package/development/docs/api/README.en.md +4 -2
- package/development/docs/api/README.md +2 -0
- package/development/docs/api/configuration-in-workflow.en.md +403 -0
- package/development/docs/api/configuration-in-workflow.md +403 -0
- package/development/docs/api/core.en.md +7 -7
- package/development/docs/api/core.md +6 -6
- package/development/docs/api/decorators.en.md +20 -0
- package/development/docs/api/decorators.md +20 -0
- package/development/docs/api/examples.en.md +1 -1
- package/development/docs/api/examples.md +1 -1
- package/development/docs/api/kits.en.md +22 -4
- package/development/docs/api/kits.md +22 -4
- package/development/docs/api/knowledge-answering.en.md +4 -1
- package/development/docs/api/knowledge-answering.md +4 -1
- package/development/docs/api/mock.en.md +2 -0
- package/development/docs/api/mock.md +2 -0
- package/development/docs/api/reference.en.md +508 -410
- package/development/docs/api/reference.md +508 -410
- package/development/docs/api/support.en.md +55 -9
- package/development/docs/api/support.md +53 -7
- package/development/docs/api/types.en.md +35 -1
- package/development/docs/api/types.md +43 -0
- package/development/docs/basic-usage.en.md +1 -1
- package/development/docs/basic-usage.md +1 -1
- package/development/docs/create-app.en.md +1 -1
- package/development/docs/examples/registration/associated.mjs +8 -0
- package/development/docs/examples/registration/independent.mjs +20 -0
- package/development/docs/examples/registration/protocol.mjs +48 -0
- package/development/docs/examples/registration/run.mjs +47 -0
- package/development/docs/examples/registration/tools.mjs +75 -0
- package/development/docs/examples/registration/workflow.mjs +109 -0
- package/development/docs/flows/knowledge-maintenance.en.md +1 -1
- package/development/docs/materials.en.md +1 -1
- package/development/docs/mechanisms.en.md +2 -2
- package/development/docs/mechanisms.md +1 -1
- package/development/docs/operations.en.md +1 -1
- package/development/docs/records.en.md +1 -1
- package/development/docs/registration.en.md +4 -4
- package/development/docs/registration.md +2 -2
- package/development/skills/agent-core-app/SKILL.md +4 -4
- package/development/skills/agent-core-app/templates/node-ts/README.md.tpl +1 -1
- package/development/skills/agent-core-app/templates/node-ts/src/catalog.ts.tpl +2 -2
- package/development/skills/agent-core-app/templates/node-ts/test/app.test.mjs.tpl +1 -1
- package/dist/cjs/capabilities/index.js +5 -12
- package/dist/cjs/capabilities/model.js +56 -12
- package/dist/cjs/capabilities/tool-conditions.js +65 -0
- package/dist/cjs/capabilities/tool-runtime.js +10 -3
- package/dist/cjs/context/audit.js +5 -8
- package/dist/cjs/context/index.js +3 -4
- package/dist/cjs/index.js +21 -17
- package/dist/cjs/kits/answering/tasks.js +5 -5
- package/dist/cjs/kits/domains/catalog.js +113 -0
- package/dist/cjs/kits/domains/index.js +20 -0
- package/dist/cjs/kits/{intents → domains}/registry.js +77 -31
- package/dist/cjs/kits/{intents → domains}/scopes.js +21 -21
- package/dist/cjs/kits/index.js +14 -13
- package/dist/cjs/kits/presentation/formats.js +110 -0
- package/dist/cjs/kits/presentation/index.js +10 -5
- package/dist/cjs/kits/reflection.js +2 -2
- package/dist/cjs/kits/text-blocks.js +101 -0
- package/dist/cjs/kits/tools.js +246 -158
- package/dist/cjs/model/index.js +2 -6
- package/dist/cjs/model/interactions/calls.js +61 -0
- package/dist/cjs/model/interactions/json-object.js +11 -11
- package/dist/cjs/model/interactions/native-functions.js +17 -23
- package/dist/cjs/model/message-diagnostics.js +13 -3
- package/dist/cjs/model/options.js +2 -0
- package/dist/cjs/model/preparation.js +39 -6
- package/dist/cjs/model/runner.js +14 -0
- package/dist/cjs/model/selection-transport.js +4 -4
- package/dist/cjs/model/token-budget.js +3 -0
- package/dist/cjs/model/transports.js +3 -2
- package/dist/cjs/structs/index.js +7 -6
- package/dist/cjs/structs/kits/presentation/formats.js +2 -0
- package/dist/cjs/structs/kits/text-blocks.js +11 -0
- package/dist/cjs/structs/model/session.js +11 -0
- package/dist/cjs/structs/support/associations.js +2 -0
- package/dist/cjs/support/associations.js +79 -0
- package/dist/cjs/support/context/snapshot.js +11 -1
- package/dist/cjs/support/decorators/index.js +45 -3
- package/dist/cjs/support/index.js +1 -0
- package/dist/cjs/support/model/capabilities.js +35 -5
- package/dist/cjs/support/model/chat-completions.js +11 -2
- package/dist/cjs/support/model/completion/calls.js +10 -56
- package/dist/cjs/support/model/preview-rules.js +11 -11
- package/dist/cjs/support/model/reply-preview.js +3 -3
- package/dist/cjs/support/model/session.js +152 -0
- package/dist/cjs/support/model/stage-transport.js +8 -8
- package/dist/cjs/support/model/transports.js +5 -2
- package/dist/cjs/support/tools.js +42 -17
- package/dist/esm/capabilities/index.d.ts +5 -10
- package/dist/esm/capabilities/index.js +5 -9
- package/dist/esm/capabilities/model.d.ts +17 -13
- package/dist/esm/capabilities/model.js +54 -10
- package/dist/esm/capabilities/tool-conditions.d.ts +9 -0
- package/dist/esm/capabilities/tool-conditions.js +59 -0
- package/dist/esm/capabilities/tool-runtime.js +10 -3
- package/dist/esm/capabilities/tools.d.ts +3 -3
- package/dist/esm/context/audit.js +5 -8
- package/dist/esm/context/index.d.ts +3 -4
- package/dist/esm/context/index.js +3 -4
- package/dist/esm/index.d.ts +19 -13
- package/dist/esm/index.js +18 -15
- package/dist/esm/kits/answering/tasks.d.ts +6 -6
- package/dist/esm/kits/answering/tasks.js +5 -5
- package/dist/esm/kits/domains/catalog.d.ts +42 -0
- package/dist/esm/kits/domains/catalog.js +110 -0
- package/dist/esm/kits/domains/index.d.ts +4 -0
- package/dist/esm/kits/domains/index.js +4 -0
- package/dist/esm/kits/domains/registry.d.ts +100 -0
- package/dist/esm/kits/{intents → domains}/registry.js +77 -31
- package/dist/esm/kits/{intents → domains}/scopes.d.ts +18 -18
- package/dist/esm/kits/{intents → domains}/scopes.js +21 -21
- package/dist/esm/kits/index.d.ts +6 -5
- package/dist/esm/kits/index.js +6 -5
- package/dist/esm/kits/presentation/formats.d.ts +42 -0
- package/dist/esm/kits/presentation/formats.js +105 -0
- package/dist/esm/kits/presentation/index.d.ts +14 -5
- package/dist/esm/kits/presentation/index.js +10 -5
- package/dist/esm/kits/reflection.js +3 -3
- package/dist/esm/kits/text-blocks.d.ts +24 -0
- package/dist/esm/kits/text-blocks.js +97 -0
- package/dist/esm/kits/tools.d.ts +69 -52
- package/dist/esm/kits/tools.js +246 -158
- package/dist/esm/model/index.d.ts +2 -6
- package/dist/esm/model/index.js +2 -6
- package/dist/esm/model/interactions/calls.d.ts +40 -0
- package/dist/esm/model/interactions/calls.js +58 -0
- package/dist/esm/model/interactions/json-object.js +11 -11
- package/dist/esm/model/interactions/native-functions.js +17 -23
- package/dist/esm/model/message-diagnostics.d.ts +6 -5
- package/dist/esm/model/message-diagnostics.js +13 -3
- package/dist/esm/model/options.js +2 -0
- package/dist/esm/model/preparation.js +39 -6
- package/dist/esm/model/runner.js +14 -0
- package/dist/esm/model/selection-transport.js +4 -4
- package/dist/esm/model/token-budget.js +3 -0
- package/dist/esm/model/transports.d.ts +2 -1
- package/dist/esm/model/transports.js +3 -2
- package/dist/esm/structs/capabilities/invocation.d.ts +1 -1
- package/dist/esm/structs/capabilities/model.d.ts +42 -11
- package/dist/esm/structs/capabilities/tools.d.ts +9 -4
- package/dist/esm/structs/common.d.ts +1 -1
- package/dist/esm/structs/index.d.ts +7 -6
- package/dist/esm/structs/index.js +7 -6
- package/dist/esm/structs/kits/answering/tasks.d.ts +2 -2
- package/dist/esm/structs/kits/{intents → domains}/catalog.d.ts +20 -20
- package/dist/esm/structs/kits/{intents → domains}/registry.d.ts +24 -21
- package/dist/esm/structs/kits/{intents → domains}/scopes.d.ts +9 -9
- package/dist/esm/structs/kits/presentation/formats.d.ts +42 -0
- package/dist/esm/structs/kits/presentation/formats.js +1 -0
- package/dist/esm/structs/kits/text-blocks.d.ts +25 -0
- package/dist/esm/structs/kits/text-blocks.js +10 -0
- package/dist/esm/structs/kits/tools.d.ts +82 -83
- package/dist/esm/structs/model/interactions.d.ts +18 -11
- package/dist/esm/structs/model/messages.d.ts +34 -2
- package/dist/esm/structs/model/runtime.d.ts +7 -0
- package/dist/esm/structs/model/session.d.ts +29 -0
- package/dist/esm/structs/model/session.js +10 -0
- package/dist/esm/structs/support/associations.d.ts +22 -0
- package/dist/esm/structs/support/associations.js +1 -0
- package/dist/esm/structs/support/model/interactions.d.ts +2 -2
- package/dist/esm/structs/support/model/messages.d.ts +6 -13
- package/dist/esm/structs/support/tools.d.ts +23 -23
- package/dist/esm/support/associations.d.ts +26 -0
- package/dist/esm/support/associations.js +76 -0
- package/dist/esm/support/context/snapshot.js +11 -1
- package/dist/esm/support/decorators/index.d.ts +13 -2
- package/dist/esm/support/decorators/index.js +40 -3
- package/dist/esm/support/decorators/pool.d.ts +6 -5
- package/dist/esm/support/decorators/types.d.ts +3 -1
- package/dist/esm/support/index.d.ts +1 -0
- package/dist/esm/support/index.js +1 -0
- package/dist/esm/support/model/capabilities.d.ts +8 -3
- package/dist/esm/support/model/capabilities.js +35 -5
- package/dist/esm/support/model/chat-completions.js +11 -2
- package/dist/esm/support/model/completion/calls.d.ts +6 -34
- package/dist/esm/support/model/completion/calls.js +8 -55
- package/dist/esm/support/model/index.d.ts +1 -1
- package/dist/esm/support/model/preview-rules.d.ts +13 -8
- package/dist/esm/support/model/preview-rules.js +11 -11
- package/dist/esm/support/model/reply-preview.d.ts +2 -2
- package/dist/esm/support/model/reply-preview.js +3 -3
- package/dist/esm/support/model/session.d.ts +61 -0
- package/dist/esm/support/model/session.js +148 -0
- package/dist/esm/support/model/stage-transport.d.ts +1 -1
- package/dist/esm/support/model/stage-transport.js +9 -9
- package/dist/esm/support/model/transports.d.ts +2 -0
- package/dist/esm/support/model/transports.js +2 -1
- package/dist/esm/support/tools.d.ts +11 -3
- package/dist/esm/support/tools.js +43 -18
- package/dist/esm/utils/catalog.d.ts +1 -1
- package/package.json +20 -6
- package/dist/cjs/execution/index.js +0 -30
- package/dist/cjs/kits/intents/catalog.js +0 -82
- package/dist/cjs/kits/intents/index.js +0 -35
- package/dist/esm/execution/index.d.ts +0 -11
- package/dist/esm/execution/index.js +0 -11
- package/dist/esm/kits/intents/catalog.d.ts +0 -39
- package/dist/esm/kits/intents/catalog.js +0 -79
- package/dist/esm/kits/intents/index.d.ts +0 -22
- package/dist/esm/kits/intents/index.js +0 -18
- package/dist/esm/kits/intents/registry.d.ts +0 -88
- /package/dist/cjs/structs/kits/{intents → domains}/catalog.js +0 -0
- /package/dist/cjs/structs/kits/{intents → domains}/registry.js +0 -0
- /package/dist/cjs/structs/kits/{intents → domains}/scopes.js +0 -0
- /package/dist/esm/structs/kits/{intents → domains}/catalog.js +0 -0
- /package/dist/esm/structs/kits/{intents → domains}/registry.js +0 -0
- /package/dist/esm/structs/kits/{intents → domains}/scopes.js +0 -0
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public surface of the model protocol layer.
|
|
3
3
|
*
|
|
4
|
-
* Re-exports the runner
|
|
5
|
-
*
|
|
6
|
-
* this module, so consumers should not import the individual files.
|
|
4
|
+
* Re-exports the runner and the provider/transport contracts. Support implementations are
|
|
5
|
+
* exported from the package root or `/support`; this Core barrel stays free of Support code.
|
|
7
6
|
*/
|
|
8
7
|
export * from './runner.js';
|
|
9
8
|
export * from '../structs/model/chat-provider.js';
|
|
10
|
-
export * from '../support/model/compatible-provider.js';
|
|
11
|
-
export * from '../support/model/transports.js';
|
|
12
|
-
export * from '../support/model/interactions/index.js';
|
|
13
9
|
export { modelRunnerDefaults } from './defaults.js';
|
package/dist/esm/model/index.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public surface of the model protocol layer.
|
|
3
3
|
*
|
|
4
|
-
* Re-exports the runner
|
|
5
|
-
*
|
|
6
|
-
* this module, so consumers should not import the individual files.
|
|
4
|
+
* Re-exports the runner and the provider/transport contracts. Support implementations are
|
|
5
|
+
* exported from the package root or `/support`; this Core barrel stays free of Support code.
|
|
7
6
|
*/
|
|
8
7
|
export * from './runner.js';
|
|
9
8
|
export * from '../structs/model/chat-provider.js';
|
|
10
|
-
export * from '../support/model/compatible-provider.js';
|
|
11
|
-
export * from '../support/model/transports.js';
|
|
12
|
-
export * from '../support/model/interactions/index.js';
|
|
13
9
|
export { modelRunnerDefaults } from './defaults.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-call delta aggregation.
|
|
3
|
+
*
|
|
4
|
+
* One algorithm is shared by completion policies, session transports and direct callers:
|
|
5
|
+
* fragments are keyed by their provider index, IDs may not conflict, and a complete call
|
|
6
|
+
* requires both an ID and a name. A complete call never hides another started but incomplete one.
|
|
7
|
+
*
|
|
8
|
+
* Exports: `AggregatedToolCall`, `ToolCallCollector`, `ToolCallFailure` and
|
|
9
|
+
* `createToolCallCollector`.
|
|
10
|
+
*/
|
|
11
|
+
import type { ModelPart } from '../../structs/model/messages.js';
|
|
12
|
+
/** One completed native tool call in provider index order. */
|
|
13
|
+
export interface AggregatedToolCall {
|
|
14
|
+
readonly index: number;
|
|
15
|
+
readonly id: string;
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly arguments: string;
|
|
18
|
+
}
|
|
19
|
+
/** Report a protocol violation and stop; callers decide how the failure is classified. */
|
|
20
|
+
export type ToolCallFailure = (message: string) => never;
|
|
21
|
+
/** Aggregation entry point for streamed function-call deltas. */
|
|
22
|
+
export interface ToolCallCollector {
|
|
23
|
+
/** Feed one part; text parts are ignored and cannot satisfy or break a call. */
|
|
24
|
+
push(part: ModelPart): void;
|
|
25
|
+
/** Calls started so far, including incomplete ones, in index order. */
|
|
26
|
+
readonly calls: readonly AggregatedToolCall[];
|
|
27
|
+
/**
|
|
28
|
+
* Finalize the calls.
|
|
29
|
+
*
|
|
30
|
+
* @throws When any started call is still missing its ID or name.
|
|
31
|
+
*/
|
|
32
|
+
complete(): readonly AggregatedToolCall[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a collector for one response.
|
|
36
|
+
*
|
|
37
|
+
* @param fail - Protocol failure factory; defaults to the Core model protocol error.
|
|
38
|
+
* @returns A collector that keeps its own state and never shares it with another response.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createToolCallCollector(fail?: ToolCallFailure): ToolCallCollector;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { modelProtocolError } from '../../utils/model-protocol.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a collector for one response.
|
|
4
|
+
*
|
|
5
|
+
* @param fail - Protocol failure factory; defaults to the Core model protocol error.
|
|
6
|
+
* @returns A collector that keeps its own state and never shares it with another response.
|
|
7
|
+
*/
|
|
8
|
+
export function createToolCallCollector(fail = modelProtocolError) {
|
|
9
|
+
const pending = new Map();
|
|
10
|
+
const ids = new Set();
|
|
11
|
+
const calls = () => [...pending.entries()]
|
|
12
|
+
.sort(([left], [right]) => left - right)
|
|
13
|
+
.map(([index, call]) => ({ index, ...call }));
|
|
14
|
+
return {
|
|
15
|
+
push(part) {
|
|
16
|
+
if (typeof part === 'string')
|
|
17
|
+
return;
|
|
18
|
+
if (!part || typeof part !== 'object' || Array.isArray(part))
|
|
19
|
+
fail('Expected a native model call');
|
|
20
|
+
const { type, index, id, name, arguments: args } = part;
|
|
21
|
+
if (type !== 'function-call-delta')
|
|
22
|
+
fail('Expected a native model call');
|
|
23
|
+
if (!Number.isInteger(index) || index < 0)
|
|
24
|
+
fail('Invalid model call index');
|
|
25
|
+
if ((id !== undefined && (typeof id !== 'string' || !id)) ||
|
|
26
|
+
(name !== undefined && typeof name !== 'string') ||
|
|
27
|
+
(args !== undefined && typeof args !== 'string'))
|
|
28
|
+
fail('Invalid model call fields');
|
|
29
|
+
let call = pending.get(index);
|
|
30
|
+
if (!call) {
|
|
31
|
+
call = { id: '', name: '', arguments: '' };
|
|
32
|
+
pending.set(index, call);
|
|
33
|
+
}
|
|
34
|
+
if (id !== undefined) {
|
|
35
|
+
if (call.id && call.id !== id)
|
|
36
|
+
fail('Conflicting model call IDs');
|
|
37
|
+
if (!call.id) {
|
|
38
|
+
if (ids.has(id))
|
|
39
|
+
fail('Duplicate model call ID');
|
|
40
|
+
ids.add(id);
|
|
41
|
+
call.id = id;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
call.name += name ?? '';
|
|
45
|
+
call.arguments += args ?? '';
|
|
46
|
+
},
|
|
47
|
+
get calls() {
|
|
48
|
+
return calls();
|
|
49
|
+
},
|
|
50
|
+
complete() {
|
|
51
|
+
const completed = calls();
|
|
52
|
+
for (const call of completed)
|
|
53
|
+
if (!call.id || !call.name)
|
|
54
|
+
fail('Incomplete model call');
|
|
55
|
+
return completed;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -22,24 +22,24 @@ export const jsonObjectInteraction = Object.freeze({
|
|
|
22
22
|
/**
|
|
23
23
|
* Build the instruction and response collector for one stage.
|
|
24
24
|
*
|
|
25
|
-
* @param
|
|
25
|
+
* @param tools - Capabilities registered for this stage; must be non-empty.
|
|
26
26
|
* @returns JSON mode options, the measured instruction and the collector factory.
|
|
27
27
|
*/
|
|
28
|
-
prepare(
|
|
29
|
-
const declarations =
|
|
28
|
+
prepare(tools) {
|
|
29
|
+
const declarations = tools.map(({ id, description, inputSchema }) => ({
|
|
30
30
|
id,
|
|
31
31
|
description,
|
|
32
32
|
input: inputSchema.jsonSchema,
|
|
33
33
|
}));
|
|
34
34
|
// Keep the wire shape after potentially long schemas so it cannot be mistaken
|
|
35
35
|
// for a schema definition or a bare capability argument object.
|
|
36
|
-
const instruction = 'Registered
|
|
36
|
+
const instruction = 'Registered tools: ' +
|
|
37
37
|
JSON.stringify(declarations) +
|
|
38
|
-
'\nReturn exactly one JSON object with exactly these two fields: {"
|
|
39
|
-
'Choose
|
|
40
|
-
JSON.stringify(
|
|
41
|
-
"; input is the chosen
|
|
42
|
-
'Do not return the schema, response_format, an array, multiple calls, prose or fences. The outer object must contain
|
|
38
|
+
'\nReturn exactly one JSON object with exactly these two fields: {"name":"registered id","input":{...}}. ' +
|
|
39
|
+
'Choose tool name from ' +
|
|
40
|
+
JSON.stringify(tools.map((capability) => capability.id)) +
|
|
41
|
+
"; input is the chosen tool's actual argument object matching its input schema. " +
|
|
42
|
+
'Do not return the schema, response_format, an array, multiple calls, prose or fences. The outer object must contain name and input.';
|
|
43
43
|
return {
|
|
44
44
|
options: { json: true },
|
|
45
45
|
schemaChars: instruction.length,
|
|
@@ -58,10 +58,10 @@ export const jsonObjectInteraction = Object.freeze({
|
|
|
58
58
|
finish() {
|
|
59
59
|
const value = parse(raw);
|
|
60
60
|
if (Object.keys(value).length !== 2 ||
|
|
61
|
-
typeof value.
|
|
61
|
+
typeof value.name !== 'string' ||
|
|
62
62
|
!Object.hasOwn(value, 'input'))
|
|
63
63
|
modelProtocolError('Invalid model selection envelope');
|
|
64
|
-
return {
|
|
64
|
+
return { toolId: value.name, input: object(value.input) };
|
|
65
65
|
},
|
|
66
66
|
};
|
|
67
67
|
},
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { modelProtocolError } from '../../utils/model-protocol.js';
|
|
11
11
|
import { parse, wireName } from './arguments.js';
|
|
12
|
+
import { createToolCallCollector } from './calls.js';
|
|
12
13
|
/**
|
|
13
14
|
* Adapter that decodes a streamed native function call.
|
|
14
15
|
*
|
|
@@ -24,15 +25,15 @@ export const nativeFunctionInteraction = Object.freeze({
|
|
|
24
25
|
* Wire names are derived from capability ids and must stay unique after mapping;
|
|
25
26
|
* a collision would make it impossible to resolve the proposed name back to an id.
|
|
26
27
|
*
|
|
27
|
-
* @param
|
|
28
|
+
* @param tools - Capabilities registered for this stage; must be non-empty.
|
|
28
29
|
* @returns Function declarations, the measured instruction and the collector factory.
|
|
29
30
|
* @throws TypeError When two capability ids map to the same wire name.
|
|
30
31
|
*/
|
|
31
|
-
prepare(
|
|
32
|
-
const names = new Map(
|
|
33
|
-
if (names.size !==
|
|
32
|
+
prepare(tools) {
|
|
33
|
+
const names = new Map(tools.map((capability) => [wireName(capability.id), capability.id]));
|
|
34
|
+
if (names.size !== tools.length)
|
|
34
35
|
throw new TypeError('Model wire name collision');
|
|
35
|
-
const functions =
|
|
36
|
+
const functions = tools.map((capability) => ({
|
|
36
37
|
name: wireName(capability.id),
|
|
37
38
|
description: capability.description,
|
|
38
39
|
parameters: capability.inputSchema.jsonSchema,
|
|
@@ -44,11 +45,12 @@ export const nativeFunctionInteraction = Object.freeze({
|
|
|
44
45
|
schemaChars: JSON.stringify(functions).length + instruction.length,
|
|
45
46
|
instruction,
|
|
46
47
|
createResponse() {
|
|
48
|
+
const collector = createToolCallCollector();
|
|
47
49
|
let raw = '';
|
|
48
|
-
let call;
|
|
49
50
|
return {
|
|
50
51
|
get outputChars() {
|
|
51
|
-
return (raw.length +
|
|
52
|
+
return (raw.length +
|
|
53
|
+
collector.calls.reduce((sum, call) => sum + call.id.length + call.name.length + call.arguments.length, 0));
|
|
52
54
|
},
|
|
53
55
|
push(part) {
|
|
54
56
|
if (typeof part === 'string') {
|
|
@@ -57,32 +59,24 @@ export const nativeFunctionInteraction = Object.freeze({
|
|
|
57
59
|
}
|
|
58
60
|
if (!part || typeof part !== 'object' || Array.isArray(part))
|
|
59
61
|
modelProtocolError('Expected a native model call');
|
|
60
|
-
const { type, index
|
|
62
|
+
const { type, index } = part;
|
|
61
63
|
if (type !== 'function-call-delta')
|
|
62
64
|
modelProtocolError('Expected a native model call');
|
|
63
65
|
if (index !== 0)
|
|
64
66
|
modelProtocolError('Expected exactly one model call', 'MODEL_MULTIPLE_CALLS');
|
|
65
|
-
|
|
66
|
-
(name !== undefined && typeof name !== 'string') ||
|
|
67
|
-
(args !== undefined && typeof args !== 'string'))
|
|
68
|
-
modelProtocolError('Invalid native model call fields');
|
|
69
|
-
call ??= { id: '', name: '', arguments: '' };
|
|
70
|
-
if (id !== undefined) {
|
|
71
|
-
if (call.id && call.id !== id)
|
|
72
|
-
modelProtocolError('Conflicting model call IDs');
|
|
73
|
-
call.id = id;
|
|
74
|
-
}
|
|
75
|
-
call.name += name ?? '';
|
|
76
|
-
call.arguments += args ?? '';
|
|
67
|
+
collector.push(part);
|
|
77
68
|
},
|
|
78
69
|
finish() {
|
|
79
|
-
|
|
70
|
+
const calls = collector.complete();
|
|
71
|
+
if (calls.length !== 1)
|
|
72
|
+
modelProtocolError('Expected exactly one model call', 'MODEL_MULTIPLE_CALLS');
|
|
73
|
+
if (raw.trim())
|
|
80
74
|
modelProtocolError('Expected one complete model call without prose');
|
|
81
|
-
const completed =
|
|
75
|
+
const completed = calls[0];
|
|
82
76
|
const capability = names.get(completed.name) ??
|
|
83
77
|
modelProtocolError('Model call is not registered for this stage');
|
|
84
78
|
return {
|
|
85
|
-
|
|
79
|
+
toolId: capability,
|
|
86
80
|
input: parse(completed.arguments),
|
|
87
81
|
call: {
|
|
88
82
|
id: completed.id,
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Redaction of model messages before they are observed or persisted.
|
|
3
3
|
*
|
|
4
|
-
* Diagnostics may keep message text, but image bytes must never leave
|
|
5
|
-
* even when full content logging is enabled.
|
|
4
|
+
* Diagnostics may keep message text, but image bytes and raw tool arguments must never leave
|
|
5
|
+
* the process, even when full content logging is enabled.
|
|
6
6
|
*
|
|
7
7
|
* Exports: `modelMessageDiagnostics`.
|
|
8
8
|
*/
|
|
9
9
|
import type { ModelMessage } from '../structs/model/messages.js';
|
|
10
10
|
/**
|
|
11
|
-
* Replace every image payload with a placeholder.
|
|
11
|
+
* Replace every image payload and raw tool argument with a placeholder.
|
|
12
12
|
*
|
|
13
13
|
* Only the `url` is substituted; the `detail` hint is kept because it is small and
|
|
14
|
-
* explains how the image was interpreted.
|
|
14
|
+
* explains how the image was interpreted. Tool call ids and names remain because they
|
|
15
|
+
* identify the proposal; raw arguments are redacted. The input array is not mutated.
|
|
15
16
|
*
|
|
16
17
|
* @param messages - Messages about to be reported.
|
|
17
|
-
* @returns New message objects
|
|
18
|
+
* @returns New message objects with redacted images and tool arguments.
|
|
18
19
|
*/
|
|
19
20
|
export declare function modelMessageDiagnostics(messages: readonly ModelMessage[]): ModelMessage[];
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Replace every image payload with a placeholder.
|
|
2
|
+
* Replace every image payload and raw tool argument with a placeholder.
|
|
3
3
|
*
|
|
4
4
|
* Only the `url` is substituted; the `detail` hint is kept because it is small and
|
|
5
|
-
* explains how the image was interpreted.
|
|
5
|
+
* explains how the image was interpreted. Tool call ids and names remain because they
|
|
6
|
+
* identify the proposal; raw arguments are redacted. The input array is not mutated.
|
|
6
7
|
*
|
|
7
8
|
* @param messages - Messages about to be reported.
|
|
8
|
-
* @returns New message objects
|
|
9
|
+
* @returns New message objects with redacted images and tool arguments.
|
|
9
10
|
*/
|
|
10
11
|
export function modelMessageDiagnostics(messages) {
|
|
11
12
|
return messages.map((message) => ({
|
|
@@ -15,5 +16,14 @@ export function modelMessageDiagnostics(messages) {
|
|
|
15
16
|
images: message.images.map((image) => ({ ...image, url: '[image omitted]' })),
|
|
16
17
|
}
|
|
17
18
|
: {}),
|
|
19
|
+
...(message.toolCalls
|
|
20
|
+
? {
|
|
21
|
+
toolCalls: message.toolCalls.map((call) => ({
|
|
22
|
+
id: call.id,
|
|
23
|
+
name: call.name,
|
|
24
|
+
arguments: '[tool arguments omitted]',
|
|
25
|
+
})),
|
|
26
|
+
}
|
|
27
|
+
: {}),
|
|
18
28
|
}));
|
|
19
29
|
}
|
|
@@ -15,6 +15,8 @@ export function snapshotModelOptions(options = {}) {
|
|
|
15
15
|
includeUsage: options.includeUsage,
|
|
16
16
|
onUsage: options.onUsage?.bind(options),
|
|
17
17
|
functions: options.functions,
|
|
18
|
+
toolChoice: options.toolChoice,
|
|
19
|
+
parallelToolCalls: options.parallelToolCalls,
|
|
18
20
|
};
|
|
19
21
|
for (const key of Object.keys(snapshot)) {
|
|
20
22
|
if (!(key in options))
|
|
@@ -35,6 +35,23 @@ function snapshotImage(image) {
|
|
|
35
35
|
(detail !== undefined && !['auto', 'low', 'high', 'original'].includes(detail)), () => new TypeError('Invalid model image'));
|
|
36
36
|
return Object.freeze({ url, ...(detail === undefined ? {} : { detail }) });
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate and freeze one assistant tool declaration.
|
|
40
|
+
*
|
|
41
|
+
* @param call - Candidate tool call.
|
|
42
|
+
* @returns A frozen tool call with only the declared fields.
|
|
43
|
+
* @throws TypeError When the id, name or raw arguments are invalid.
|
|
44
|
+
*/
|
|
45
|
+
function snapshotToolCall(call) {
|
|
46
|
+
breakWhile(!call || typeof call !== 'object' || Array.isArray(call), () => new TypeError('Invalid model tool call'));
|
|
47
|
+
const { id, name, arguments: args } = call;
|
|
48
|
+
breakWhile(typeof id !== 'string' ||
|
|
49
|
+
!id ||
|
|
50
|
+
typeof name !== 'string' ||
|
|
51
|
+
!name ||
|
|
52
|
+
typeof args !== 'string', () => new TypeError('Invalid model tool call'));
|
|
53
|
+
return Object.freeze({ id, name, arguments: args });
|
|
54
|
+
}
|
|
38
55
|
/**
|
|
39
56
|
* Snapshot a dynamic transport once, preserving its collector factory receiver.
|
|
40
57
|
*
|
|
@@ -95,19 +112,35 @@ export function preparedInputSize(base, prepared) {
|
|
|
95
112
|
breakWhile(!Array.isArray(base), () => new TypeError('Model messages must be an array'));
|
|
96
113
|
const snapshot = Array.from(base, (message) => {
|
|
97
114
|
breakWhile(!message || typeof message !== 'object' || Array.isArray(message), () => new TypeError('Invalid model message'));
|
|
98
|
-
const { role, content, images } = message;
|
|
99
|
-
|
|
115
|
+
const { role, content, images, toolCalls, toolCallId } = message;
|
|
116
|
+
const assistant = role === 'assistant';
|
|
117
|
+
const tool = role === 'tool';
|
|
118
|
+
breakWhile(!['system', 'user', 'assistant', 'tool'].includes(role) ||
|
|
100
119
|
typeof content !== 'string' ||
|
|
101
|
-
(images !== undefined && !Array.isArray(images)
|
|
120
|
+
(images !== undefined && (!Array.isArray(images) || role !== 'user')) ||
|
|
121
|
+
(toolCalls !== undefined && (!Array.isArray(toolCalls) || !assistant)) ||
|
|
122
|
+
(toolCallId !== undefined &&
|
|
123
|
+
(!tool || typeof toolCallId !== 'string' || toolCallId.length === 0)) ||
|
|
124
|
+
(tool && (typeof toolCallId !== 'string' || toolCallId.length === 0)), () => new TypeError('Invalid model message'));
|
|
102
125
|
return Object.freeze({
|
|
103
126
|
role,
|
|
104
127
|
content,
|
|
105
|
-
...(images === undefined
|
|
128
|
+
...(images === undefined
|
|
129
|
+
? {}
|
|
130
|
+
: { images: Object.freeze(Array.from(images, snapshotImage)) }),
|
|
131
|
+
...(toolCalls === undefined
|
|
132
|
+
? {}
|
|
133
|
+
: { toolCalls: Object.freeze(Array.from(toolCalls, snapshotToolCall)) }),
|
|
134
|
+
...(toolCallId === undefined ? {} : { toolCallId }),
|
|
106
135
|
});
|
|
107
136
|
});
|
|
108
137
|
const messages = Object.freeze(modelInputMessages(snapshot, prepared.instruction).map((message) => Object.freeze(message)));
|
|
109
|
-
const
|
|
110
|
-
const
|
|
138
|
+
const contentChars = snapshot.reduce((sum, message) => sum + message.content.length, 0);
|
|
139
|
+
const messageChars = snapshot.reduce((sum, message) => sum +
|
|
140
|
+
message.content.length +
|
|
141
|
+
(message.toolCalls?.reduce((callSum, call) => callSum + call.id.length + call.name.length + call.arguments.length, 0) ?? 0) +
|
|
142
|
+
(message.toolCallId?.length ?? 0), 0);
|
|
143
|
+
const instructionChars = messages.reduce((sum, message) => sum + message.content.length, 0) - contentChars;
|
|
111
144
|
const functions = prepared.options.functions;
|
|
112
145
|
const schemaChars = functions
|
|
113
146
|
? (functionSizes.get(functions) ?? JSON.stringify(functions).length)
|
package/dist/esm/model/runner.js
CHANGED
|
@@ -628,6 +628,20 @@ export class ModelRunner {
|
|
|
628
628
|
catch {
|
|
629
629
|
/* best-effort metadata */
|
|
630
630
|
}
|
|
631
|
+
try {
|
|
632
|
+
const calls = response.calls;
|
|
633
|
+
if (calls?.length) {
|
|
634
|
+
step.calls = calls.map((call) => ({
|
|
635
|
+
id: call.id,
|
|
636
|
+
name: call.name,
|
|
637
|
+
argumentChars: call.argumentChars,
|
|
638
|
+
...(call.toolId === undefined ? {} : { toolId: call.toolId }),
|
|
639
|
+
}));
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
catch {
|
|
643
|
+
/* best-effort metadata */
|
|
644
|
+
}
|
|
631
645
|
};
|
|
632
646
|
const accountOutput = () => {
|
|
633
647
|
const outputChars = response.outputChars;
|
|
@@ -30,7 +30,7 @@ export function createModelTransport(registration) {
|
|
|
30
30
|
const adapter = registration.adapter ?? nativeFunctionInteraction;
|
|
31
31
|
if (registration.requireStrictArguments && !adapter.features.strictArguments)
|
|
32
32
|
throw new TypeError(`Model interaction does not support strict arguments: ${adapter.id}`);
|
|
33
|
-
const source = registration.
|
|
33
|
+
const source = registration.tools, createSource = typeof source === 'function' ? source.bind(registration) : undefined;
|
|
34
34
|
const prepare = adapter.prepare.bind(adapter), options = Object.freeze(snapshotModelOptions(registration.options));
|
|
35
35
|
return Object.freeze({
|
|
36
36
|
id: registration.id,
|
|
@@ -40,8 +40,8 @@ export function createModelTransport(registration) {
|
|
|
40
40
|
: source;
|
|
41
41
|
const definitions = [...catalog.values()];
|
|
42
42
|
if (!definitions.length)
|
|
43
|
-
throw new TypeError('Model stage requires registered
|
|
44
|
-
const
|
|
43
|
+
throw new TypeError('Model stage requires registered tools');
|
|
44
|
+
const toolIds = new Set(definitions.map((capability) => capability.id));
|
|
45
45
|
const prepared = synchronous(prepare(definitions), 'Model interaction preparation must be synchronous');
|
|
46
46
|
const createResponse = prepared.createResponse.bind(prepared), resolve = catalog.resolve.bind(catalog);
|
|
47
47
|
return {
|
|
@@ -62,7 +62,7 @@ export function createModelTransport(registration) {
|
|
|
62
62
|
finish() {
|
|
63
63
|
const selection = synchronous(buffer.finish(), 'Model selection parsers must be synchronous');
|
|
64
64
|
call = selection.call;
|
|
65
|
-
if (!
|
|
65
|
+
if (!toolIds.has(selection.toolId))
|
|
66
66
|
modelProtocolError('Model capability is unavailable in this prepared call');
|
|
67
67
|
return synchronous(resolve(selection, { stageId }), 'Model result parsers must be synchronous');
|
|
68
68
|
},
|
|
@@ -49,6 +49,9 @@ export function countModelInput(budget, messages, options) {
|
|
|
49
49
|
const snapshot = messages.map((message) => ({
|
|
50
50
|
...message,
|
|
51
51
|
...(message.images ? { images: message.images.map((image) => ({ ...image })) } : {}),
|
|
52
|
+
...(message.toolCalls
|
|
53
|
+
? { toolCalls: message.toolCalls.map((call) => ({ ...call })) }
|
|
54
|
+
: {}),
|
|
52
55
|
}));
|
|
53
56
|
const count = budget.countTokens({
|
|
54
57
|
messages: snapshot,
|
|
@@ -8,9 +8,10 @@ import type { ModelTransportDefinition } from '../structs/model/runtime.js';
|
|
|
8
8
|
*
|
|
9
9
|
* @param id - Unique transport id, also used as the typed handle in `ModelRunner`.
|
|
10
10
|
* @param options - Optional request options; only `temperature` is honored.
|
|
11
|
+
* @param trim - Trim surrounding whitespace from the final text; defaults to true.
|
|
11
12
|
* @returns A frozen transport definition.
|
|
12
13
|
*/
|
|
13
|
-
export declare function createPlainTextTransport<const Id extends string>(id: Id, options?: Pick<ModelOptions, 'temperature'
|
|
14
|
+
export declare function createPlainTextTransport<const Id extends string>(id: Id, options?: Pick<ModelOptions, 'temperature'>, trim?: boolean): ModelTransportDefinition<string> & {
|
|
14
15
|
readonly id: Id;
|
|
15
16
|
};
|
|
16
17
|
/**
|
|
@@ -45,16 +45,17 @@ function textResponse(decode) {
|
|
|
45
45
|
*
|
|
46
46
|
* @param id - Unique transport id, also used as the typed handle in `ModelRunner`.
|
|
47
47
|
* @param options - Optional request options; only `temperature` is honored.
|
|
48
|
+
* @param trim - Trim surrounding whitespace from the final text; defaults to true.
|
|
48
49
|
* @returns A frozen transport definition.
|
|
49
50
|
*/
|
|
50
|
-
export function createPlainTextTransport(id, options = {}) {
|
|
51
|
+
export function createPlainTextTransport(id, options = {}, trim = true) {
|
|
51
52
|
const settings = Object.freeze({ ...snapshotModelOptions(options), json: false });
|
|
52
53
|
return Object.freeze({
|
|
53
54
|
id,
|
|
54
55
|
prepare: (_stageId) => ({
|
|
55
56
|
options: settings,
|
|
56
57
|
schemaChars: 0,
|
|
57
|
-
createResponse: () => textResponse((raw) => raw.trim()),
|
|
58
|
+
createResponse: () => textResponse((raw) => (trim ? raw.trim() : raw)),
|
|
58
59
|
}),
|
|
59
60
|
});
|
|
60
61
|
}
|
|
@@ -47,7 +47,7 @@ export interface InvocationHandler<Input, Context> {
|
|
|
47
47
|
*/
|
|
48
48
|
call(input: Input, context: Context, execution: import('./tools.js').ToolExecutionContext): void;
|
|
49
49
|
}
|
|
50
|
-
/** Optional
|
|
50
|
+
/** Optional tools the lifecycle resolves from the host context for one invocation. */
|
|
51
51
|
export interface ToolInvocationPorts<Context> {
|
|
52
52
|
/** Explicit recorder selected for this invocation only. */
|
|
53
53
|
readonly logger?: (context: Context) => import('../debug.js').SubFlowLogger | undefined;
|
|
@@ -5,18 +5,42 @@
|
|
|
5
5
|
* host value. Registration snapshots the schema and pins the resolver, so a request can project a
|
|
6
6
|
* sealed subset without cloning handlers.
|
|
7
7
|
*
|
|
8
|
-
* Exports: `
|
|
9
|
-
* `ModelSelection`, `
|
|
8
|
+
* Exports: `ModelTool`, `ModelToolRegistration`, `RegisteredModelTool`,
|
|
9
|
+
* `ModelSelection`, `ModelToolSource`, `ModelToolCatalog`.
|
|
10
10
|
*/
|
|
11
11
|
import type { SchemaAdapter, ReadonlyCatalog } from '../common.js';
|
|
12
|
-
/**
|
|
13
|
-
export interface
|
|
12
|
+
/** A model proposal, not an authorization or execution receipt. */
|
|
13
|
+
export interface ToolProposal {
|
|
14
|
+
readonly toolId: string;
|
|
15
|
+
readonly input: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Read-only host data without changing explicit any/unknown erasure into an object constraint. */
|
|
18
|
+
export type ToolContext<Context> = unknown extends Context ? Context : Readonly<Context>;
|
|
19
|
+
/** Demand-facing hints attached to one Tool; no independent identity is created. */
|
|
20
|
+
export interface IntentOptions<Context> {
|
|
21
|
+
/** Optional demand-facing description; otherwise the tool description is reused. */
|
|
22
|
+
readonly description?: string;
|
|
23
|
+
/** Synchronous participation predicate. */
|
|
24
|
+
readonly when?: (context: ToolContext<Context>) => boolean;
|
|
25
|
+
/** Allowed continuation delegates, not an execution sequence. */
|
|
26
|
+
readonly delegates?: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/** Demand-discovery metadata; it has no identity independent of its tool. */
|
|
29
|
+
export type AsIntent<Context> = true | string | ((context: ToolContext<Context>) => boolean) | IntentOptions<Context>;
|
|
30
|
+
/** Activation is independent of participation in demand discovery. */
|
|
31
|
+
export type ToolCondition<Context> = boolean | ((context: ToolContext<Context>) => boolean);
|
|
32
|
+
/** Common selectable model interface; resolution proposes a value without business execution. */
|
|
33
|
+
export interface ModelTool<Input = unknown, Output = Input, Context = any> {
|
|
14
34
|
/** Unique id within its registry; never blank. */
|
|
15
35
|
readonly id: string;
|
|
16
36
|
/** Model-visible description explaining when the capability applies. */
|
|
17
37
|
readonly description: string;
|
|
18
38
|
/** Schema describing the arguments; must be an object schema. */
|
|
19
39
|
readonly inputSchema: SchemaAdapter<Input>;
|
|
40
|
+
/** Omitted means active. Authorization remains a separate execution boundary. */
|
|
41
|
+
readonly active?: ToolCondition<Context>;
|
|
42
|
+
/** Omitted means this tool is not advertised by withIntent(). */
|
|
43
|
+
readonly asIntent?: AsIntent<Context>;
|
|
20
44
|
/**
|
|
21
45
|
* Converts validated arguments into the value handed back to the caller.
|
|
22
46
|
*
|
|
@@ -27,9 +51,11 @@ export interface ModelCapability<Input = unknown, Output = Input> {
|
|
|
27
51
|
}>): Output;
|
|
28
52
|
}
|
|
29
53
|
/** Registration form: input typing is erased, output typing is preserved. */
|
|
30
|
-
export type
|
|
54
|
+
export type ModelToolRegistration<Output = unknown> = Omit<ModelTool<any, Output>, 'resolve'> & {
|
|
55
|
+
readonly resolve?: ModelTool<any, Output>['resolve'];
|
|
56
|
+
};
|
|
31
57
|
/** Frozen snapshot stored by a registry after schema validation. */
|
|
32
|
-
export type
|
|
58
|
+
export type RegisteredModelTool<Output = unknown> = Readonly<ModelTool<unknown, Output>>;
|
|
33
59
|
/** A model's chosen capability together with its parsed arguments. */
|
|
34
60
|
export type ModelSelection = {
|
|
35
61
|
/** Arguments exactly as produced by the model, before schema parsing. */
|
|
@@ -41,15 +67,20 @@ export type ModelSelection = {
|
|
|
41
67
|
argumentChars: number;
|
|
42
68
|
};
|
|
43
69
|
/** Capability the selection resolved to. */
|
|
44
|
-
readonly
|
|
70
|
+
readonly toolId: string;
|
|
45
71
|
};
|
|
46
|
-
/** Minimal source a stage needs: enumerate
|
|
47
|
-
export interface
|
|
48
|
-
values(): IterableIterator<
|
|
72
|
+
/** Minimal source a stage needs: enumerate tools and resolve one selection. */
|
|
73
|
+
export interface ModelToolSource<Output = unknown> {
|
|
74
|
+
values(): IterableIterator<RegisteredModelTool<Output>>;
|
|
49
75
|
/** Resolves one selection; throws when the capability is absent from this source. */
|
|
50
76
|
resolve(selection: ModelSelection, context: Readonly<{
|
|
51
77
|
stageId: string;
|
|
52
78
|
}>): Output;
|
|
53
79
|
}
|
|
54
80
|
/** A compiled entity catalog also supports the minimal stage source contract. */
|
|
55
|
-
export type
|
|
81
|
+
export type ModelToolCatalog<Output = unknown> = ReadonlyCatalog<RegisteredModelTool<Output>> & ModelToolSource<Output> & {
|
|
82
|
+
/** Explicit selection, optionally filtered against a host context. */
|
|
83
|
+
select(ids: readonly string[], context?: unknown): ModelToolCatalog<Output>;
|
|
84
|
+
/** Demand-facing active tools; no workflow node or invocation is implied. */
|
|
85
|
+
withIntent(context: unknown): ModelToolCatalog<Output>;
|
|
86
|
+
};
|