@ifc-lite/ids-agent 0.0.0-stage → 0.2.1
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/LICENSE +373 -0
- package/README.md +144 -2
- package/dist/bridges.d.ts +163 -0
- package/dist/bridges.d.ts.map +1 -0
- package/dist/bridges.js +6 -0
- package/dist/bridges.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/modes.d.ts +30 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +34 -0
- package/dist/modes.js.map +1 -0
- package/dist/prompts/system-v1.d.ts +19 -0
- package/dist/prompts/system-v1.d.ts.map +1 -0
- package/dist/prompts/system-v1.js +43 -0
- package/dist/prompts/system-v1.js.map +1 -0
- package/dist/proposal/proposal.d.ts +72 -0
- package/dist/proposal/proposal.d.ts.map +1 -0
- package/dist/proposal/proposal.js +60 -0
- package/dist/proposal/proposal.js.map +1 -0
- package/dist/proposal/view-model.d.ts +66 -0
- package/dist/proposal/view-model.d.ts.map +1 -0
- package/dist/proposal/view-model.js +94 -0
- package/dist/proposal/view-model.js.map +1 -0
- package/dist/providers/anthropic.d.ts +45 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +107 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/openai.d.ts +60 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +92 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/runner/context.d.ts +21 -0
- package/dist/runner/context.d.ts.map +1 -0
- package/dist/runner/context.js +25 -0
- package/dist/runner/context.js.map +1 -0
- package/dist/runner/loop.d.ts +96 -0
- package/dist/runner/loop.d.ts.map +1 -0
- package/dist/runner/loop.js +194 -0
- package/dist/runner/loop.js.map +1 -0
- package/dist/runner/privacy.d.ts +71 -0
- package/dist/runner/privacy.d.ts.map +1 -0
- package/dist/runner/privacy.js +72 -0
- package/dist/runner/privacy.js.map +1 -0
- package/dist/runner/receipt.d.ts +48 -0
- package/dist/runner/receipt.d.ts.map +1 -0
- package/dist/runner/receipt.js +29 -0
- package/dist/runner/receipt.js.map +1 -0
- package/dist/sandbox/handles.d.ts +22 -0
- package/dist/sandbox/handles.d.ts.map +1 -0
- package/dist/sandbox/handles.js +67 -0
- package/dist/sandbox/handles.js.map +1 -0
- package/dist/sandbox/nodes.d.ts +11 -0
- package/dist/sandbox/nodes.d.ts.map +1 -0
- package/dist/sandbox/nodes.js +38 -0
- package/dist/sandbox/nodes.js.map +1 -0
- package/dist/sandbox/sandbox.d.ts +110 -0
- package/dist/sandbox/sandbox.d.ts.map +1 -0
- package/dist/sandbox/sandbox.js +125 -0
- package/dist/sandbox/sandbox.js.map +1 -0
- package/dist/testing/doubles.d.ts +20 -0
- package/dist/testing/doubles.d.ts.map +1 -0
- package/dist/testing/doubles.js +105 -0
- package/dist/testing/doubles.js.map +1 -0
- package/dist/testing/index.d.ts +8 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +11 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/transports.d.ts +48 -0
- package/dist/testing/transports.d.ts.map +1 -0
- package/dist/testing/transports.js +70 -0
- package/dist/testing/transports.js.map +1 -0
- package/dist/tools/act-tools.d.ts +13 -0
- package/dist/tools/act-tools.d.ts.map +1 -0
- package/dist/tools/act-tools.js +115 -0
- package/dist/tools/act-tools.js.map +1 -0
- package/dist/tools/ask-user.d.ts +3 -0
- package/dist/tools/ask-user.d.ts.map +1 -0
- package/dist/tools/ask-user.js +62 -0
- package/dist/tools/ask-user.js.map +1 -0
- package/dist/tools/bsdd-tools.d.ts +8 -0
- package/dist/tools/bsdd-tools.d.ts.map +1 -0
- package/dist/tools/bsdd-tools.js +64 -0
- package/dist/tools/bsdd-tools.js.map +1 -0
- package/dist/tools/context.d.ts +27 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +21 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/ids-read.d.ts +26 -0
- package/dist/tools/ids-read.d.ts.map +1 -0
- package/dist/tools/ids-read.js +74 -0
- package/dist/tools/ids-read.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +22 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/model-tools.d.ts +3 -0
- package/dist/tools/model-tools.d.ts.map +1 -0
- package/dist/tools/model-tools.js +100 -0
- package/dist/tools/model-tools.js.map +1 -0
- package/dist/tools/op-schema.d.ts +23 -0
- package/dist/tools/op-schema.d.ts.map +1 -0
- package/dist/tools/op-schema.js +57 -0
- package/dist/tools/op-schema.js.map +1 -0
- package/dist/tools/rank.d.ts +3 -0
- package/dist/tools/rank.d.ts.map +1 -0
- package/dist/tools/rank.js +66 -0
- package/dist/tools/rank.js.map +1 -0
- package/dist/tools/registry.d.ts +59 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +61 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/schema-tools.d.ts +3 -0
- package/dist/tools/schema-tools.d.ts.map +1 -0
- package/dist/tools/schema-tools.js +127 -0
- package/dist/tools/schema-tools.js.map +1 -0
- package/dist/worker-bridge.d.ts +47 -0
- package/dist/worker-bridge.d.ts.map +1 -0
- package/dist/worker-bridge.js +97 -0
- package/dist/worker-bridge.js.map +1 -0
- package/package.json +79 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAGV,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EACd,MAAM,oDAAoD,CAAC;AAC5D,OAAO,EAAqC,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAA2B,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE1K,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6GAA6G;IAC7G,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uFAAuF;IACvF,eAAe,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED,mDAAmD;AACnD,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AAoB9D,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,gBAAgB,EAAE,CAczH;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,aAAa,EAAE,CASnG;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,uBAA4B,GAAG,uBAAuB,CAqBvH;AAaD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,CAWnE;AAED,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,uBAAuB,EAAE,OAAO,GAAE,uBAA4B,GAAG,iBAAiB,CAO5H"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { anthropicUsage } from '@ifc-lite/ai';
|
|
5
|
+
const PROVIDER = 'anthropic';
|
|
6
|
+
const TASK_BUDGET_MIN = 20_000;
|
|
7
|
+
function assistantBlocks(content) {
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const block of content) {
|
|
10
|
+
if (block.type === 'text') {
|
|
11
|
+
if (block.text)
|
|
12
|
+
out.push({ type: 'text', text: block.text });
|
|
13
|
+
}
|
|
14
|
+
else if (block.type === 'tool_call') {
|
|
15
|
+
out.push({ type: 'tool_use', id: block.id, name: block.name, input: block.input ?? {} });
|
|
16
|
+
}
|
|
17
|
+
else if (block.provider === PROVIDER) {
|
|
18
|
+
// Sent back exactly as the API returned it (thinking signatures must not change).
|
|
19
|
+
out.push(block.value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
export function toAnthropicMessages(messages, context) {
|
|
25
|
+
return messages.map((m, i) => {
|
|
26
|
+
if (m.role === 'user') {
|
|
27
|
+
const text = [];
|
|
28
|
+
if (i === 0 && context)
|
|
29
|
+
text.push({ type: 'text', text: context });
|
|
30
|
+
text.push({ type: 'text', text: m.content });
|
|
31
|
+
return { role: 'user', content: text };
|
|
32
|
+
}
|
|
33
|
+
if (m.role === 'assistant')
|
|
34
|
+
return { role: 'assistant', content: assistantBlocks(m.content) };
|
|
35
|
+
return {
|
|
36
|
+
role: 'user',
|
|
37
|
+
content: m.results.map((r) => ({ type: 'tool_result', tool_use_id: r.callId, content: r.content, is_error: r.isError })),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export function toAnthropicTools(call, eager) {
|
|
42
|
+
return call.tools.map((t) => ({
|
|
43
|
+
name: t.name,
|
|
44
|
+
description: t.description,
|
|
45
|
+
// `inputSchema` is a JSON Schema object with `type: 'object'` (the registry builds it).
|
|
46
|
+
input_schema: { type: 'object', ...t.inputSchema },
|
|
47
|
+
...(t.strict ? { strict: true } : {}),
|
|
48
|
+
...(eager ? { eager_input_streaming: true } : {}),
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
export function buildAnthropicParams(call, options = {}) {
|
|
52
|
+
const betas = [];
|
|
53
|
+
const taskBudget = options.taskBudgets !== false && call.taskBudget !== undefined ? Math.max(TASK_BUDGET_MIN, call.taskBudget) : undefined;
|
|
54
|
+
if (taskBudget !== undefined)
|
|
55
|
+
betas.push('task-budgets-2026-03-13');
|
|
56
|
+
if (options.fallbacks !== false)
|
|
57
|
+
betas.push('server-side-fallback-2026-07-01');
|
|
58
|
+
return {
|
|
59
|
+
model: call.model,
|
|
60
|
+
max_tokens: call.maxOutputTokens,
|
|
61
|
+
system: [{ type: 'text', text: call.system, cache_control: { type: 'ephemeral' } }],
|
|
62
|
+
messages: toAnthropicMessages(call.messages, call.context),
|
|
63
|
+
tools: toAnthropicTools(call, options.eagerInputStreaming !== false),
|
|
64
|
+
tool_choice: { type: 'auto' },
|
|
65
|
+
thinking: { type: 'adaptive', display: options.thinkingDisplay ?? 'summarized' },
|
|
66
|
+
cache_control: { type: 'ephemeral' },
|
|
67
|
+
output_config: {
|
|
68
|
+
...(call.effort ? { effort: call.effort } : {}),
|
|
69
|
+
...(taskBudget !== undefined ? { task_budget: { type: 'tokens', total: taskBudget } } : {}),
|
|
70
|
+
},
|
|
71
|
+
...(options.fallbacks !== false ? { fallbacks: 'default' } : {}),
|
|
72
|
+
...(betas.length ? { betas } : {}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const STOP = {
|
|
76
|
+
end_turn: 'end_turn', stop_sequence: 'end_turn', tool_use: 'tool_use', max_tokens: 'max_tokens',
|
|
77
|
+
model_context_window_exceeded: 'max_tokens', pause_turn: 'pause_turn', refusal: 'refusal',
|
|
78
|
+
};
|
|
79
|
+
function fromBlock(block) {
|
|
80
|
+
if (block.type === 'text')
|
|
81
|
+
return { type: 'text', text: block.text };
|
|
82
|
+
if (block.type === 'tool_use')
|
|
83
|
+
return { type: 'tool_call', id: block.id, name: block.name, input: block.input };
|
|
84
|
+
return { type: 'opaque', provider: PROVIDER, value: block };
|
|
85
|
+
}
|
|
86
|
+
export function fromAnthropicMessage(message) {
|
|
87
|
+
const details = message.stop_details;
|
|
88
|
+
return {
|
|
89
|
+
content: message.content.map(fromBlock),
|
|
90
|
+
stopReason: (message.stop_reason && STOP[message.stop_reason]) || 'other',
|
|
91
|
+
usage: anthropicUsage(message.usage),
|
|
92
|
+
servedModel: message.model,
|
|
93
|
+
...(message.stop_reason === 'refusal' && details
|
|
94
|
+
? { refusal: { category: details.category ?? null, explanation: details.explanation ?? null } }
|
|
95
|
+
: {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** A tool-turn transport over an Anthropic SDK client. */
|
|
99
|
+
export function anthropicTransport(client, options = {}) {
|
|
100
|
+
return async (call) => {
|
|
101
|
+
const stream = client.beta.messages.stream(buildAnthropicParams(call, options), { signal: call.signal });
|
|
102
|
+
stream.on('text', (delta) => call.onText(delta));
|
|
103
|
+
stream.on('thinking', (delta) => call.onThinking(delta));
|
|
104
|
+
return fromAnthropicMessage(await stream.finalMessage());
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAmC/D,OAAO,EAAE,cAAc,EAA8H,MAAM,cAAc,CAAC;AAgB1K,MAAM,QAAQ,GAAG,WAAW,CAAC;AAC7B,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,SAAS,eAAe,CAAC,OAAgC;IACvD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,IAAI,KAAK,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACtC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC;QAC3F,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACvC,kFAAkF;YAClF,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAA8B,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAoC,EAAE,OAA2B;IACnG,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAoB,EAAE;QAC7C,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,IAAI,GAA4B,EAAE,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,IAAI,OAAO;gBAAE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YACnE,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;YAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9F,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,aAAsB,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;SAClI,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAiC,EAAE,KAAc;IAChF,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,wFAAwF;QACxF,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;QAClD,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClD,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAkB,EAAE,UAAmC,EAAE;IAC5F,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,KAAK,KAAK,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3I,IAAI,UAAU,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACpE,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC/E,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,UAAU,EAAE,IAAI,CAAC,eAAe;QAChC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC;QACnF,QAAQ,EAAE,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC;QAC1D,KAAK,EAAE,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,mBAAmB,KAAK,KAAK,CAAC;QACpE,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,IAAI,YAAY,EAAE;QAChF,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;QACpC,aAAa,EAAE;YACb,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5F;QACD,GAAG,CAAC,OAAO,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,IAAI,GAAiD;IACzD,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY;IAC/F,6BAA6B,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS;CAC1F,CAAC;AAEF,SAAS,SAAS,CAAC,KAAuB;IACxC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;IACrE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAoB;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QACvC,UAAU,EAAE,CAAC,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,OAAO;QACzE,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC;QACpC,WAAW,EAAE,OAAO,CAAC,KAAK;QAC1B,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO;YAC9C,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI,EAAE,EAAE;YAC/F,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,kBAAkB,CAAC,MAA+B,EAAE,UAAmC,EAAE;IACvG,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACzG,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QACzD,OAAO,oBAAoB,CAAC,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-compatible Chat Completions adapter for the tool-turn contract
|
|
3
|
+
* (provider two, `06-ai-agent.md` §3: offered for a mode only where it
|
|
4
|
+
* passes that mode's eval gate). One non-streaming request per turn through
|
|
5
|
+
* the host's `fetch`; the host supplies the key and base URL.
|
|
6
|
+
*
|
|
7
|
+
* Tool inputs arrive as JSON text; one that does not parse is passed on as
|
|
8
|
+
* `rawInput` so the registry answers `INVALID_JSON` instead of running it.
|
|
9
|
+
* `strict` is not sent: OpenAI strict mode requires every property to be
|
|
10
|
+
* required, which optional tool fields are not. The registry validates.
|
|
11
|
+
*/
|
|
12
|
+
import { type ToolTurn, type ToolTurnCall, type ToolTurnTransport } from '@ifc-lite/ai';
|
|
13
|
+
export interface OpenAiAdapterConfig {
|
|
14
|
+
readonly apiKey: string;
|
|
15
|
+
/** Default `https://api.openai.com/v1`. */
|
|
16
|
+
readonly baseUrl?: string;
|
|
17
|
+
/** Send `reasoning_effort` (reasoning models only). Default false. */
|
|
18
|
+
readonly reasoningEffort?: boolean;
|
|
19
|
+
}
|
|
20
|
+
type ChatMessage = {
|
|
21
|
+
role: 'system' | 'user';
|
|
22
|
+
content: string;
|
|
23
|
+
} | {
|
|
24
|
+
role: 'assistant';
|
|
25
|
+
content: string | null;
|
|
26
|
+
tool_calls?: {
|
|
27
|
+
id: string;
|
|
28
|
+
type: 'function';
|
|
29
|
+
function: {
|
|
30
|
+
name: string;
|
|
31
|
+
arguments: string;
|
|
32
|
+
};
|
|
33
|
+
}[];
|
|
34
|
+
} | {
|
|
35
|
+
role: 'tool';
|
|
36
|
+
tool_call_id: string;
|
|
37
|
+
content: string;
|
|
38
|
+
};
|
|
39
|
+
export declare function toChatMessages(call: Pick<ToolTurnCall, 'system' | 'context' | 'messages'>): ChatMessage[];
|
|
40
|
+
interface ChatResponse {
|
|
41
|
+
model?: string;
|
|
42
|
+
choices?: {
|
|
43
|
+
finish_reason?: string | null;
|
|
44
|
+
message?: {
|
|
45
|
+
content?: string | null;
|
|
46
|
+
refusal?: string | null;
|
|
47
|
+
tool_calls?: {
|
|
48
|
+
id?: string;
|
|
49
|
+
function?: {
|
|
50
|
+
name?: string;
|
|
51
|
+
arguments?: string;
|
|
52
|
+
};
|
|
53
|
+
}[];
|
|
54
|
+
};
|
|
55
|
+
}[];
|
|
56
|
+
}
|
|
57
|
+
export declare function fromChatResponse(body: ChatResponse): ToolTurn;
|
|
58
|
+
export declare function openAiTransport(config: OpenAiAdapterConfig, fetchImpl?: typeof fetch): ToolTurnTransport;
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAA2C,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAiD,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEhL,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,EAAE,CAAA;CAAE,GAC7I;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC,GAAG,WAAW,EAAE,CAgBzG;AAMD,UAAU,YAAY;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,OAAO,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,UAAU,CAAC,EAAE;gBAAE,EAAE,CAAC,EAAE,MAAM,CAAC;gBAAC,QAAQ,CAAC,EAAE;oBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;oBAAC,SAAS,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,EAAE,CAAA;SAAE,CAAC;KAClJ,EAAE,CAAC;CACL;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,QAAQ,CAyB7D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,mBAAmB,EAAE,SAAS,GAAE,OAAO,KAAa,GAAG,iBAAiB,CAqB/G"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* OpenAI-compatible Chat Completions adapter for the tool-turn contract
|
|
6
|
+
* (provider two, `06-ai-agent.md` §3: offered for a mode only where it
|
|
7
|
+
* passes that mode's eval gate). One non-streaming request per turn through
|
|
8
|
+
* the host's `fetch`; the host supplies the key and base URL.
|
|
9
|
+
*
|
|
10
|
+
* Tool inputs arrive as JSON text; one that does not parse is passed on as
|
|
11
|
+
* `rawInput` so the registry answers `INVALID_JSON` instead of running it.
|
|
12
|
+
* `strict` is not sent: OpenAI strict mode requires every property to be
|
|
13
|
+
* required, which optional tool fields are not. The registry validates.
|
|
14
|
+
*/
|
|
15
|
+
import { chatCompletionsUsage } from '@ifc-lite/ai';
|
|
16
|
+
export function toChatMessages(call) {
|
|
17
|
+
const out = [{ role: 'system', content: call.system }];
|
|
18
|
+
call.messages.forEach((m, i) => {
|
|
19
|
+
if (m.role === 'user') {
|
|
20
|
+
out.push({ role: 'user', content: i === 0 && call.context ? `${call.context}\n\n${m.content}` : m.content });
|
|
21
|
+
}
|
|
22
|
+
else if (m.role === 'assistant') {
|
|
23
|
+
const text = m.content.filter((b) => b.type === 'text').map((b) => (b.type === 'text' ? b.text : '')).join('');
|
|
24
|
+
const calls = m.content.flatMap((b) => (b.type === 'tool_call'
|
|
25
|
+
? [{ id: b.id, type: 'function', function: { name: b.name, arguments: b.rawInput ?? JSON.stringify(b.input ?? {}) } }]
|
|
26
|
+
: []));
|
|
27
|
+
out.push({ role: 'assistant', content: text || null, ...(calls.length ? { tool_calls: calls } : {}) });
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
for (const r of m.results)
|
|
31
|
+
out.push({ role: 'tool', tool_call_id: r.callId, content: r.content });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
const STOP = {
|
|
37
|
+
stop: 'end_turn', tool_calls: 'tool_use', function_call: 'tool_use', length: 'max_tokens', content_filter: 'refusal',
|
|
38
|
+
};
|
|
39
|
+
export function fromChatResponse(body) {
|
|
40
|
+
const choice = body.choices?.[0];
|
|
41
|
+
const content = [];
|
|
42
|
+
const text = choice?.message?.content;
|
|
43
|
+
if (typeof text === 'string' && text)
|
|
44
|
+
content.push({ type: 'text', text });
|
|
45
|
+
for (const [i, tc] of (choice?.message?.tool_calls ?? []).entries()) {
|
|
46
|
+
const raw = tc.function?.arguments ?? '';
|
|
47
|
+
let input;
|
|
48
|
+
let parsed = true;
|
|
49
|
+
try {
|
|
50
|
+
input = raw ? JSON.parse(raw) : {};
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
parsed = false; // reported to the model as INVALID_JSON by the registry
|
|
54
|
+
}
|
|
55
|
+
content.push({ type: 'tool_call', id: tc.id ?? `call-${i}`, name: tc.function?.name ?? '', input, ...(parsed ? {} : { rawInput: raw }) });
|
|
56
|
+
}
|
|
57
|
+
const refusal = choice?.message?.refusal;
|
|
58
|
+
const finish = choice?.finish_reason ?? '';
|
|
59
|
+
return {
|
|
60
|
+
content,
|
|
61
|
+
stopReason: refusal ? 'refusal' : STOP[finish] ?? 'other',
|
|
62
|
+
usage: chatCompletionsUsage(body),
|
|
63
|
+
...(body.model ? { servedModel: body.model } : {}),
|
|
64
|
+
...(refusal ? { refusal: { category: null, explanation: refusal } } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function openAiTransport(config, fetchImpl = fetch) {
|
|
68
|
+
const baseUrl = (config.baseUrl ?? 'https://api.openai.com/v1').replace(/\/+$/, '');
|
|
69
|
+
return async (call) => {
|
|
70
|
+
const response = await fetchImpl(`${baseUrl}/chat/completions`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${config.apiKey}` },
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
model: call.model,
|
|
75
|
+
max_completion_tokens: call.maxOutputTokens,
|
|
76
|
+
messages: toChatMessages(call),
|
|
77
|
+
tools: call.tools.map((t) => ({ type: 'function', function: { name: t.name, description: t.description, parameters: t.inputSchema } })),
|
|
78
|
+
tool_choice: 'auto',
|
|
79
|
+
...(config.reasoningEffort && call.effort ? { reasoning_effort: call.effort === 'xhigh' || call.effort === 'max' ? 'high' : call.effort } : {}),
|
|
80
|
+
}),
|
|
81
|
+
signal: call.signal,
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok)
|
|
84
|
+
throw new Error(`the AI provider answered HTTP ${response.status}`);
|
|
85
|
+
const turn = fromChatResponse(await response.json());
|
|
86
|
+
for (const b of turn.content)
|
|
87
|
+
if (b.type === 'text')
|
|
88
|
+
call.onText(b.text);
|
|
89
|
+
return turn;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The volatile context block of a run: the document summary and the user's
|
|
3
|
+
* attachments. It is built ONCE at the start of a run and sent unchanged
|
|
4
|
+
* with every request, after the cached prefix (tools, system prompt), so
|
|
5
|
+
* the conversation stays append-only. The model reads later document state
|
|
6
|
+
* through `ids_read`.
|
|
7
|
+
*
|
|
8
|
+
* Attachment text is untrusted: it is fenced and labelled as data so the
|
|
9
|
+
* model treats instructions inside it as content (prompt-injection guard,
|
|
10
|
+
* `06-ai-agent.md` §6.7).
|
|
11
|
+
*/
|
|
12
|
+
import type { StudioDocument } from '@ifc-lite/ids-authoring';
|
|
13
|
+
import type { ContextPart } from './privacy.js';
|
|
14
|
+
export interface Attachment {
|
|
15
|
+
/** Shown to the model as a label; never a file path. */
|
|
16
|
+
label: string;
|
|
17
|
+
text: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function buildContext(doc: StudioDocument, attachments: readonly Attachment[]): ContextPart[];
|
|
20
|
+
export declare function joinContext(parts: readonly ContextPart[]): string;
|
|
21
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/runner/context.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAOD,wBAAgB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,CAYnG;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAEjE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { summarizeDocument } from '../tools/ids-read.js';
|
|
5
|
+
/** Strip anything that could close the data fence early. */
|
|
6
|
+
function fenced(text) {
|
|
7
|
+
return text.replace(/<\/?untrusted_data[^>]*>/gi, '[tag removed]');
|
|
8
|
+
}
|
|
9
|
+
export function buildContext(doc, attachments) {
|
|
10
|
+
const parts = [{
|
|
11
|
+
source: 'document',
|
|
12
|
+
label: 'Document summary',
|
|
13
|
+
text: `Current IDS document (node ids for ops; read details with ids_read):\n${JSON.stringify(summarizeDocument(doc))}`,
|
|
14
|
+
}];
|
|
15
|
+
attachments.forEach((a, i) => parts.push({
|
|
16
|
+
source: 'attachments',
|
|
17
|
+
label: a.label || `Attachment ${i + 1}`,
|
|
18
|
+
text: `<untrusted_data source="attachment ${i + 1}" label="${a.label.replace(/["<>]/g, '')}">\n${fenced(a.text)}\n</untrusted_data>`,
|
|
19
|
+
}));
|
|
20
|
+
return parts;
|
|
21
|
+
}
|
|
22
|
+
export function joinContext(parts) {
|
|
23
|
+
return parts.map((p) => p.text).join('\n\n');
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runner/context.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAgB/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAQzD,4DAA4D;AAC5D,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,eAAe,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAmB,EAAE,WAAkC;IAClF,MAAM,KAAK,GAAkB,CAAC;YAC5B,MAAM,EAAE,UAAU;YAClB,KAAK,EAAE,kBAAkB;YACzB,IAAI,EAAE,yEAAyE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAE;SACxH,CAAC,CAAC;IACH,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QACvC,MAAM,EAAE,aAAa;QACrB,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE;QACvC,IAAI,EAAE,sCAAsC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB;KACrI,CAAC,CAAC,CAAC;IACJ,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAA6B;IACvD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The agent loop (`06-ai-agent.md` §4, ADR-008).
|
|
3
|
+
*
|
|
4
|
+
* request → model turn → tool calls → results → next turn, until one of:
|
|
5
|
+
* the model ends its turn, the root budget is exhausted, the same failure
|
|
6
|
+
* signature comes back twice in a row (no progress), the caller cancels, a
|
|
7
|
+
* request times out, the wall-clock cap passes, the model refuses, or it is
|
|
8
|
+
* cut off without a usable answer.
|
|
9
|
+
*
|
|
10
|
+
* Every turn goes through `runToolTurn` from `@ifc-lite/ai` (budget,
|
|
11
|
+
* deadline, cancel, receipt). Tools run one at a time, in the order the model
|
|
12
|
+
* called them, against the sandbox; their results go back in one message.
|
|
13
|
+
* Whatever the stop reason, the run returns the proposal built so far.
|
|
14
|
+
*/
|
|
15
|
+
import { type RootBudget, type ToolTurnMessage, type ToolTurnTransport, type UsageReceipt } from '@ifc-lite/ai';
|
|
16
|
+
import { type GateContext, type LintContext, type StudioDocument, type Uuid } from '@ifc-lite/ids-authoring';
|
|
17
|
+
import { type AskUserHandler, type BsddClient, type ModelBridge } from '../bridges.js';
|
|
18
|
+
import { type AgentMode } from '../prompts/system-v1.js';
|
|
19
|
+
import type { AgentRunStatus, Proposal } from '../proposal/proposal.js';
|
|
20
|
+
import { type Attachment } from './context.js';
|
|
21
|
+
import type { SentRequest } from './privacy.js';
|
|
22
|
+
import { type ModelPricing } from './receipt.js';
|
|
23
|
+
/** The model the agent uses unless the host chooses another (D3: the viewer assistant's default). */
|
|
24
|
+
export declare const DEFAULT_AGENT_MODEL = "claude-opus-5-5";
|
|
25
|
+
export type AgentEvent = {
|
|
26
|
+
type: 'text';
|
|
27
|
+
delta: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'thinking';
|
|
30
|
+
delta: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: 'request';
|
|
33
|
+
index: number;
|
|
34
|
+
} | {
|
|
35
|
+
type: 'receipt';
|
|
36
|
+
receipt: UsageReceipt;
|
|
37
|
+
} | {
|
|
38
|
+
type: 'tool-call';
|
|
39
|
+
callId: string;
|
|
40
|
+
name: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'tool-result';
|
|
43
|
+
callId: string;
|
|
44
|
+
name: string;
|
|
45
|
+
ok: boolean;
|
|
46
|
+
summary: string;
|
|
47
|
+
} | {
|
|
48
|
+
type: 'stopped';
|
|
49
|
+
status: AgentRunStatus;
|
|
50
|
+
message?: string;
|
|
51
|
+
};
|
|
52
|
+
export interface AgentRunOptions {
|
|
53
|
+
transport: ToolTurnTransport;
|
|
54
|
+
/** Default `DEFAULT_AGENT_MODEL`. */
|
|
55
|
+
model?: string;
|
|
56
|
+
/** Recorded on receipts, e.g. `anthropic`, `openai`, `replay`. */
|
|
57
|
+
route?: string;
|
|
58
|
+
mode: AgentMode;
|
|
59
|
+
request: string;
|
|
60
|
+
attachments?: readonly Attachment[];
|
|
61
|
+
doc: StudioDocument;
|
|
62
|
+
gate: GateContext;
|
|
63
|
+
lint: LintContext;
|
|
64
|
+
modelBridge?: ModelBridge;
|
|
65
|
+
bsdd?: BsddClient;
|
|
66
|
+
/** Default: the first choice (headless, non-interactive). */
|
|
67
|
+
askUser?: AskUserHandler;
|
|
68
|
+
/** Default: the mode's root budget. Pass a restored budget to resume spending from it. */
|
|
69
|
+
budget?: RootBudget;
|
|
70
|
+
limits?: {
|
|
71
|
+
/** Whole-run cap. Default 10 minutes. */
|
|
72
|
+
wallClockMs?: number;
|
|
73
|
+
/** Per-request deadline. Default 5 minutes. */
|
|
74
|
+
requestTimeoutMs?: number;
|
|
75
|
+
/** The route's hard output ceiling. Default 64k. */
|
|
76
|
+
routeCeiling?: number;
|
|
77
|
+
/** Tool results longer than this are cut (with a note). Default 16k characters. */
|
|
78
|
+
maxResultChars?: number;
|
|
79
|
+
};
|
|
80
|
+
pricing?: ModelPricing;
|
|
81
|
+
signal?: AbortSignal;
|
|
82
|
+
runId?: Uuid;
|
|
83
|
+
onEvent?: (event: AgentEvent) => void;
|
|
84
|
+
}
|
|
85
|
+
export interface AgentRun {
|
|
86
|
+
runId: Uuid;
|
|
87
|
+
status: AgentRunStatus;
|
|
88
|
+
message?: string;
|
|
89
|
+
proposal: Proposal;
|
|
90
|
+
/** Every message of the conversation, in order (requests sent prefixes of it). */
|
|
91
|
+
transcript: ToolTurnMessage[];
|
|
92
|
+
/** What each request carried, for the privacy view. */
|
|
93
|
+
sent: SentRequest[];
|
|
94
|
+
}
|
|
95
|
+
export declare function runAgent(options: AgentRunOptions): Promise<AgentRun>;
|
|
96
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/runner/loop.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAoD,KAAK,UAAU,EAAmB,KAAK,eAAe,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AACnL,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACrH,OAAO,EAAe,KAAK,cAAc,EAAE,KAAK,UAAU,EAAqB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAEvH,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,KAAK,EAAE,cAAc,EAAiB,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGvF,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAA+B,KAAK,YAAY,EAAwC,MAAM,cAAc,CAAC;AAEpH,qGAAqG;AACrG,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACpC,GAAG,EAAE,cAAc,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,0FAA0F;IAC1F,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE;QACP,yCAAyC;QACzC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,+CAA+C;QAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,oDAAoD;QACpD,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,mFAAmF;QACnF,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,kFAAkF;IAClF,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,uDAAuD;IACvD,IAAI,EAAE,WAAW,EAAE,CAAC;CACrB;AAsBD,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6H1E"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* The agent loop (`06-ai-agent.md` §4, ADR-008).
|
|
6
|
+
*
|
|
7
|
+
* request → model turn → tool calls → results → next turn, until one of:
|
|
8
|
+
* the model ends its turn, the root budget is exhausted, the same failure
|
|
9
|
+
* signature comes back twice in a row (no progress), the caller cancels, a
|
|
10
|
+
* request times out, the wall-clock cap passes, the model refuses, or it is
|
|
11
|
+
* cut off without a usable answer.
|
|
12
|
+
*
|
|
13
|
+
* Every turn goes through `runToolTurn` from `@ifc-lite/ai` (budget,
|
|
14
|
+
* deadline, cancel, receipt). Tools run one at a time, in the order the model
|
|
15
|
+
* called them, against the sandbox; their results go back in one message.
|
|
16
|
+
* Whatever the stop reason, the run returns the proposal built so far.
|
|
17
|
+
*/
|
|
18
|
+
import { createRootBudget, runToolTurn } from '@ifc-lite/ai';
|
|
19
|
+
import { uuidv7 } from '@ifc-lite/ids-authoring';
|
|
20
|
+
import { firstChoice } from '../bridges.js';
|
|
21
|
+
import { MODES } from '../modes.js';
|
|
22
|
+
import { SYSTEM_PROMPT_VERSION, systemPrompt } from '../prompts/system-v1.js';
|
|
23
|
+
import { brief, createSandbox } from '../sandbox/sandbox.js';
|
|
24
|
+
import { registryFor } from '../tools/index.js';
|
|
25
|
+
import { buildContext, joinContext } from './context.js';
|
|
26
|
+
import { costOf, sha256Hex, totalsOf } from './receipt.js';
|
|
27
|
+
/** The model the agent uses unless the host chooses another (D3: the viewer assistant's default). */
|
|
28
|
+
export const DEFAULT_AGENT_MODEL = 'claude-opus-5-5';
|
|
29
|
+
function serialise(data, max) {
|
|
30
|
+
const text = JSON.stringify(data);
|
|
31
|
+
return text.length <= max ? text : `${text.slice(0, max)}… [truncated: ${text.length - max} more characters; narrow the request]`;
|
|
32
|
+
}
|
|
33
|
+
async function previewsFor(sandbox, bridge, signal) {
|
|
34
|
+
const previews = {};
|
|
35
|
+
if (!bridge || signal.aborted)
|
|
36
|
+
return previews;
|
|
37
|
+
const touched = [...new Set(sandbox.batches.flatMap((b) => b.specIds))].slice(0, 20);
|
|
38
|
+
for (const specId of touched) {
|
|
39
|
+
const index = sandbox.doc.nodes.specs.findIndex((s) => s.id === specId);
|
|
40
|
+
if (index < 0)
|
|
41
|
+
continue;
|
|
42
|
+
const spec = sandbox.doc.ids.specifications[index];
|
|
43
|
+
previews[specId] = await bridge.count({
|
|
44
|
+
applicability: spec.applicability.facets, requirements: spec.requirements.map((r) => r.facet), ifcVersions: spec.ifcVersions,
|
|
45
|
+
}, signal);
|
|
46
|
+
}
|
|
47
|
+
return previews;
|
|
48
|
+
}
|
|
49
|
+
export async function runAgent(options) {
|
|
50
|
+
const mode = MODES[options.mode];
|
|
51
|
+
const model = options.model ?? DEFAULT_AGENT_MODEL;
|
|
52
|
+
const route = options.route ?? 'agent';
|
|
53
|
+
const runId = options.runId ?? uuidv7();
|
|
54
|
+
const limits = { wallClockMs: 600_000, requestTimeoutMs: 300_000, routeCeiling: 64_000, maxResultChars: 16_000, ...options.limits };
|
|
55
|
+
const emit = options.onEvent ?? (() => undefined);
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const abort = () => controller.abort(options.signal?.reason);
|
|
58
|
+
if (options.signal?.aborted)
|
|
59
|
+
abort();
|
|
60
|
+
options.signal?.addEventListener('abort', abort, { once: true });
|
|
61
|
+
const sandbox = createSandbox({ doc: options.doc, gate: options.gate, lint: options.lint, runId, model, ...(mode.opGuard ? { opGuard: mode.opGuard } : {}) });
|
|
62
|
+
const registry = registryFor(mode, { model: Boolean(options.modelBridge), bsdd: Boolean(options.bsdd) });
|
|
63
|
+
const tools = registry.specs();
|
|
64
|
+
const system = systemPrompt(options.mode);
|
|
65
|
+
const contextParts = buildContext(options.doc, options.attachments ?? []);
|
|
66
|
+
const context = joinContext(contextParts);
|
|
67
|
+
const budget = options.budget ?? createRootBudget(mode.budget);
|
|
68
|
+
const questions = [];
|
|
69
|
+
const askUser = options.askUser ?? firstChoice;
|
|
70
|
+
const recordingAskUser = async (question, signal) => {
|
|
71
|
+
const picked = await askUser(question, signal);
|
|
72
|
+
questions.push({ id: question.id, question: question.question, choices: question.choices.map((c) => c.label), picked });
|
|
73
|
+
return picked;
|
|
74
|
+
};
|
|
75
|
+
const transcript = [{ role: 'user', content: options.request }];
|
|
76
|
+
const sent = [];
|
|
77
|
+
const receipts = [];
|
|
78
|
+
const toolCalls = [];
|
|
79
|
+
const startedAt = Date.now();
|
|
80
|
+
let status = 'completed';
|
|
81
|
+
let message;
|
|
82
|
+
let finalText = '';
|
|
83
|
+
let lastSignature = '';
|
|
84
|
+
try {
|
|
85
|
+
if (mode.needsModel && !options.modelBridge) {
|
|
86
|
+
status = 'error';
|
|
87
|
+
message = `${options.mode} mode needs a loaded model.`;
|
|
88
|
+
}
|
|
89
|
+
while (status === 'completed') {
|
|
90
|
+
if (controller.signal.aborted) {
|
|
91
|
+
status = 'cancelled';
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
const elapsed = Date.now() - startedAt;
|
|
95
|
+
if (elapsed >= limits.wallClockMs) {
|
|
96
|
+
status = 'wall-clock';
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
const index = sent.length;
|
|
100
|
+
sent.push({ index, at: Date.now(), model, route, promptVersion: SYSTEM_PROMPT_VERSION, system, context: contextParts,
|
|
101
|
+
messageCount: transcript.length, toolNames: tools.map((t) => t.name) });
|
|
102
|
+
emit({ type: 'request', index });
|
|
103
|
+
const outcome = await runToolTurn({
|
|
104
|
+
model, route, transport: options.transport, system, context, messages: [...transcript], tools,
|
|
105
|
+
effort: mode.effort, taskBudget: mode.taskBudget, maxOutputTokens: mode.maxOutputTokens, routeCeiling: limits.routeCeiling,
|
|
106
|
+
budget, signal: controller.signal, timeoutMs: Math.min(limits.requestTimeoutMs, limits.wallClockMs - elapsed),
|
|
107
|
+
onText: (delta) => emit({ type: 'text', delta }), onThinking: (delta) => emit({ type: 'thinking', delta }),
|
|
108
|
+
}, { onReceipt: (receipt) => { receipts.push(receipt); emit({ type: 'receipt', receipt }); } });
|
|
109
|
+
if (outcome.kind === 'refused') {
|
|
110
|
+
sent.pop();
|
|
111
|
+
status = 'budget-exhausted';
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
if (outcome.kind === 'cancelled') {
|
|
115
|
+
status = 'cancelled';
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
if (outcome.kind === 'timeout') {
|
|
119
|
+
status = 'timeout';
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
if (outcome.kind === 'error') {
|
|
123
|
+
status = 'error';
|
|
124
|
+
message = outcome.message;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
const { turn } = outcome;
|
|
128
|
+
transcript.push({ role: 'assistant', content: turn.content });
|
|
129
|
+
const text = turn.content.filter((b) => b.type === 'text').map((b) => b.text).join('');
|
|
130
|
+
if (text.trim())
|
|
131
|
+
finalText = text;
|
|
132
|
+
if (turn.stopReason === 'refusal') {
|
|
133
|
+
status = 'refused';
|
|
134
|
+
message = turn.refusal?.explanation ?? turn.refusal?.category ?? undefined;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
if (turn.stopReason === 'pause_turn')
|
|
138
|
+
continue;
|
|
139
|
+
const calls = turn.content.filter((b) => b.type === 'tool_call');
|
|
140
|
+
if (calls.length === 0) {
|
|
141
|
+
if (turn.stopReason === 'max_tokens')
|
|
142
|
+
status = 'truncated';
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
const results = [];
|
|
146
|
+
const signature = [];
|
|
147
|
+
for (const call of calls) {
|
|
148
|
+
emit({ type: 'tool-call', callId: call.id, name: call.name });
|
|
149
|
+
const started = Date.now();
|
|
150
|
+
// A call cut off at the output ceiling may parse as a silently shortened object: never run it.
|
|
151
|
+
const result = turn.stopReason === 'max_tokens'
|
|
152
|
+
? { ok: false, summary: `${call.name}: cut off`, data: { ok: false, error: 'Your output was cut off before this call was complete; it was not run. Send a smaller batch.' }, signature: [`TRUNCATED:${call.name}`] }
|
|
153
|
+
: await registry.call(call.name, call.input, call.rawInput, {
|
|
154
|
+
sandbox, gate: options.gate, askUser: recordingAskUser, signal: controller.signal, callId: call.id,
|
|
155
|
+
...(options.modelBridge ? { model: options.modelBridge } : {}), ...(options.bsdd ? { bsdd: options.bsdd } : {}),
|
|
156
|
+
});
|
|
157
|
+
toolCalls.push({ turn: index, name: call.name, ok: result.ok, summary: result.summary, ms: Date.now() - started });
|
|
158
|
+
emit({ type: 'tool-result', callId: call.id, name: call.name, ok: result.ok, summary: result.summary });
|
|
159
|
+
results.push({ callId: call.id, content: serialise(result.data, limits.maxResultChars), isError: !result.ok });
|
|
160
|
+
signature.push(...(result.signature ?? []));
|
|
161
|
+
}
|
|
162
|
+
transcript.push({ role: 'tool', results });
|
|
163
|
+
const key = [...new Set(signature)].sort().join('|');
|
|
164
|
+
if (key && key === lastSignature) {
|
|
165
|
+
status = 'no-progress';
|
|
166
|
+
message = `The same problems came back twice: ${[...new Set(signature)].slice(0, 5).join(', ')}`;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
lastSignature = key;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
options.signal?.removeEventListener('abort', abort);
|
|
174
|
+
}
|
|
175
|
+
const previews = status === 'completed' ? await previewsFor(sandbox, options.modelBridge, controller.signal) : {};
|
|
176
|
+
const totals = totalsOf(receipts);
|
|
177
|
+
const receipt = {
|
|
178
|
+
runId, mode: options.mode, model, promptVersion: SYSTEM_PROMPT_VERSION, requests: receipts, toolCalls, totals,
|
|
179
|
+
...(options.pricing ? { costUsd: costOf(totals, options.pricing) } : {}),
|
|
180
|
+
payloadDigest: await sha256Hex(JSON.stringify(sent.map((s) => ({ ...s, messages: transcript.slice(0, s.messageCount) })))),
|
|
181
|
+
};
|
|
182
|
+
emit({ type: 'stopped', status, ...(message ? { message } : {}) });
|
|
183
|
+
return {
|
|
184
|
+
runId, status, ...(message ? { message } : {}), transcript, sent,
|
|
185
|
+
proposal: {
|
|
186
|
+
runId, mode: options.mode, model, promptVersion: SYSTEM_PROMPT_VERSION, status, summary: finalText,
|
|
187
|
+
base: { docId: options.doc.docId, specs: options.doc.nodes.specs.map((s, i) => ({ specId: s.id, name: options.doc.ids.specifications[i].name })) },
|
|
188
|
+
batches: [...sandbox.batches], unresolved: [...sandbox.unresolved], questions,
|
|
189
|
+
diagnostics: sandbox.diagnostics().filter((d) => d.severity !== 'info').map(brief),
|
|
190
|
+
draft: sandbox.doc, previews, receipt,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=loop.js.map
|