@finalai/agent-provider 0.1.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.
Potentially problematic release.
This version of @finalai/agent-provider might be problematic. Click here for more details.
- package/README.md +12 -0
- package/dist/modules/channel-context.d.mts +102 -0
- package/dist/modules/channel-context.mjs +52 -0
- package/dist/modules/channel-context.mjs.map +7 -0
- package/dist/modules/channel-socket.d.mts +65 -0
- package/dist/modules/channel-socket.mjs +188 -0
- package/dist/modules/channel-socket.mjs.map +7 -0
- package/dist/modules/channel.d.mts +382 -0
- package/dist/modules/channel.mjs +146 -0
- package/dist/modules/channel.mjs.map +7 -0
- package/dist/modules/conformance/agent.d.mts +20 -0
- package/dist/modules/conformance/agent.mjs +623 -0
- package/dist/modules/conformance/agent.mjs.map +7 -0
- package/dist/modules/conformance/fixtures.d.mts +41 -0
- package/dist/modules/conformance/fixtures.mjs +190 -0
- package/dist/modules/conformance/fixtures.mjs.map +7 -0
- package/dist/modules/conformance/harness-kit.d.mts +82 -0
- package/dist/modules/conformance/harness-kit.mjs +1303 -0
- package/dist/modules/conformance/harness-kit.mjs.map +7 -0
- package/dist/modules/conformance/image.d.mts +2 -0
- package/dist/modules/conformance/image.mjs +79 -0
- package/dist/modules/conformance/image.mjs.map +7 -0
- package/dist/modules/conformance/index.d.mts +8 -0
- package/dist/modules/conformance/index.mjs +12 -0
- package/dist/modules/conformance/index.mjs.map +7 -0
- package/dist/modules/conformance/local-harness.d.mts +25 -0
- package/dist/modules/conformance/local-harness.mjs +108 -0
- package/dist/modules/conformance/local-harness.mjs.map +7 -0
- package/dist/modules/conformance/protocol.d.mts +30 -0
- package/dist/modules/conformance/protocol.mjs +56 -0
- package/dist/modules/conformance/protocol.mjs.map +7 -0
- package/dist/modules/conformance/sandbox-kit.d.mts +19 -0
- package/dist/modules/conformance/sandbox-kit.mjs +320 -0
- package/dist/modules/conformance/sandbox-kit.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/chat-completions.d.mts +30 -0
- package/dist/modules/conformance/scripted-model/chat-completions.mjs +125 -0
- package/dist/modules/conformance/scripted-model/chat-completions.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/directives.d.mts +84 -0
- package/dist/modules/conformance/scripted-model/directives.mjs +304 -0
- package/dist/modules/conformance/scripted-model/directives.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/handler.d.mts +14 -0
- package/dist/modules/conformance/scripted-model/handler.mjs +133 -0
- package/dist/modules/conformance/scripted-model/handler.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/index.d.mts +6 -0
- package/dist/modules/conformance/scripted-model/index.mjs +7 -0
- package/dist/modules/conformance/scripted-model/index.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/messages.d.mts +39 -0
- package/dist/modules/conformance/scripted-model/messages.mjs +139 -0
- package/dist/modules/conformance/scripted-model/messages.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/responses.d.mts +62 -0
- package/dist/modules/conformance/scripted-model/responses.mjs +273 -0
- package/dist/modules/conformance/scripted-model/responses.mjs.map +7 -0
- package/dist/modules/conformance/scripted-model/sse.d.mts +15 -0
- package/dist/modules/conformance/scripted-model/sse.mjs +75 -0
- package/dist/modules/conformance/scripted-model/sse.mjs.map +7 -0
- package/dist/modules/conformance/v1-agent.d.mts +24 -0
- package/dist/modules/conformance/v1-agent.mjs +40 -0
- package/dist/modules/conformance/v1-agent.mjs.map +7 -0
- package/dist/modules/credential-routes.d.mts +24 -0
- package/dist/modules/credential-routes.mjs +25 -0
- package/dist/modules/credential-routes.mjs.map +7 -0
- package/dist/modules/credentials.d.mts +206 -0
- package/dist/modules/credentials.mjs +207 -0
- package/dist/modules/credentials.mjs.map +7 -0
- package/dist/modules/dynamic.d.mts +32 -0
- package/dist/modules/dynamic.mjs +77 -0
- package/dist/modules/dynamic.mjs.map +7 -0
- package/dist/modules/harness.d.mts +397 -0
- package/dist/modules/harness.mjs +213 -0
- package/dist/modules/harness.mjs.map +7 -0
- package/dist/modules/index.d.mts +15 -0
- package/dist/modules/index.mjs +40 -0
- package/dist/modules/index.mjs.map +7 -0
- package/dist/modules/json.d.mts +12 -0
- package/dist/modules/json.mjs +19 -0
- package/dist/modules/json.mjs.map +7 -0
- package/dist/modules/local-channel-socket.d.mts +23 -0
- package/dist/modules/local-channel-socket.mjs +141 -0
- package/dist/modules/local-channel-socket.mjs.map +7 -0
- package/dist/modules/manifest.d.mts +558 -0
- package/dist/modules/manifest.mjs +266 -0
- package/dist/modules/manifest.mjs.map +7 -0
- package/dist/modules/mcp-content.d.mts +21 -0
- package/dist/modules/mcp-content.mjs +86 -0
- package/dist/modules/mcp-content.mjs.map +7 -0
- package/dist/modules/provider-ref.d.mts +29 -0
- package/dist/modules/provider-ref.mjs +55 -0
- package/dist/modules/provider-ref.mjs.map +7 -0
- package/dist/modules/sandbox/bytes.d.mts +9 -0
- package/dist/modules/sandbox/bytes.mjs +154 -0
- package/dist/modules/sandbox/bytes.mjs.map +7 -0
- package/dist/modules/sandbox/client.d.mts +51 -0
- package/dist/modules/sandbox/client.mjs +500 -0
- package/dist/modules/sandbox/client.mjs.map +7 -0
- package/dist/modules/sandbox/confined-files.d.mts +22 -0
- package/dist/modules/sandbox/confined-files.mjs +142 -0
- package/dist/modules/sandbox/confined-files.mjs.map +7 -0
- package/dist/modules/sandbox/convenience.d.mts +10 -0
- package/dist/modules/sandbox/convenience.mjs +116 -0
- package/dist/modules/sandbox/convenience.mjs.map +7 -0
- package/dist/modules/sandbox/editor.d.mts +49 -0
- package/dist/modules/sandbox/editor.mjs +43 -0
- package/dist/modules/sandbox/editor.mjs.map +7 -0
- package/dist/modules/sandbox/frame-channel.d.mts +47 -0
- package/dist/modules/sandbox/frame-channel.mjs +153 -0
- package/dist/modules/sandbox/frame-channel.mjs.map +7 -0
- package/dist/modules/sandbox/index.d.mts +18 -0
- package/dist/modules/sandbox/index.mjs +70 -0
- package/dist/modules/sandbox/index.mjs.map +7 -0
- package/dist/modules/sandbox/mcp-channel.d.mts +9 -0
- package/dist/modules/sandbox/mcp-channel.mjs +77 -0
- package/dist/modules/sandbox/mcp-channel.mjs.map +7 -0
- package/dist/modules/sandbox/mcp-hosted.d.mts +46 -0
- package/dist/modules/sandbox/mcp-hosted.mjs +221 -0
- package/dist/modules/sandbox/mcp-hosted.mjs.map +7 -0
- package/dist/modules/sandbox/mcp-search.d.mts +51 -0
- package/dist/modules/sandbox/mcp-search.mjs +129 -0
- package/dist/modules/sandbox/mcp-search.mjs.map +7 -0
- package/dist/modules/sandbox/mcp-shell.d.mts +21 -0
- package/dist/modules/sandbox/mcp-shell.mjs +205 -0
- package/dist/modules/sandbox/mcp-shell.mjs.map +7 -0
- package/dist/modules/sandbox/mcp-testing.d.mts +11 -0
- package/dist/modules/sandbox/mcp-testing.mjs +33 -0
- package/dist/modules/sandbox/mcp-testing.mjs.map +7 -0
- package/dist/modules/sandbox/mcp.d.mts +83 -0
- package/dist/modules/sandbox/mcp.mjs +971 -0
- package/dist/modules/sandbox/mcp.mjs.map +7 -0
- package/dist/modules/sandbox/memory-sandbox.d.mts +32 -0
- package/dist/modules/sandbox/memory-sandbox.mjs +416 -0
- package/dist/modules/sandbox/memory-sandbox.mjs.map +7 -0
- package/dist/modules/sandbox/memory-shell.d.mts +29 -0
- package/dist/modules/sandbox/memory-shell.mjs +278 -0
- package/dist/modules/sandbox/memory-shell.mjs.map +7 -0
- package/dist/modules/sandbox/open-scope-node.d.mts +4 -0
- package/dist/modules/sandbox/open-scope-node.mjs +19 -0
- package/dist/modules/sandbox/open-scope-node.mjs.map +7 -0
- package/dist/modules/sandbox/open-scope.d.mts +16 -0
- package/dist/modules/sandbox/open-scope.mjs +66 -0
- package/dist/modules/sandbox/open-scope.mjs.map +7 -0
- package/dist/modules/sandbox/paths.d.mts +7 -0
- package/dist/modules/sandbox/paths.mjs +50 -0
- package/dist/modules/sandbox/paths.mjs.map +7 -0
- package/dist/modules/sandbox/rpc-peer.d.mts +35 -0
- package/dist/modules/sandbox/rpc-peer.mjs +224 -0
- package/dist/modules/sandbox/rpc-peer.mjs.map +7 -0
- package/dist/modules/sandbox/seeds.d.mts +26 -0
- package/dist/modules/sandbox/seeds.mjs +228 -0
- package/dist/modules/sandbox/seeds.mjs.map +7 -0
- package/dist/modules/sandbox/server.d.mts +66 -0
- package/dist/modules/sandbox/server.mjs +567 -0
- package/dist/modules/sandbox/server.mjs.map +7 -0
- package/dist/modules/sandbox/snapshots.d.mts +49 -0
- package/dist/modules/sandbox/snapshots.mjs +55 -0
- package/dist/modules/sandbox/snapshots.mjs.map +7 -0
- package/dist/modules/sandbox/stream-mux.d.mts +18 -0
- package/dist/modules/sandbox/stream-mux.mjs +285 -0
- package/dist/modules/sandbox/stream-mux.mjs.map +7 -0
- package/dist/modules/sandbox/testing.d.mts +25 -0
- package/dist/modules/sandbox/testing.mjs +64 -0
- package/dist/modules/sandbox/testing.mjs.map +7 -0
- package/dist/modules/sandbox/types.d.mts +352 -0
- package/dist/modules/sandbox/types.mjs +86 -0
- package/dist/modules/sandbox/types.mjs.map +7 -0
- package/dist/modules/sandbox/wire.d.mts +671 -0
- package/dist/modules/sandbox/wire.mjs +537 -0
- package/dist/modules/sandbox/wire.mjs.map +7 -0
- package/dist/modules/sandbox/workspace-root.d.mts +8 -0
- package/dist/modules/sandbox/workspace-root.mjs +79 -0
- package/dist/modules/sandbox/workspace-root.mjs.map +7 -0
- package/dist/modules/schemas.d.mts +121 -0
- package/dist/modules/schemas.mjs +146 -0
- package/dist/modules/schemas.mjs.map +7 -0
- package/dist/modules/semantic-events.d.mts +31 -0
- package/dist/modules/semantic-events.mjs +23 -0
- package/dist/modules/semantic-events.mjs.map +7 -0
- package/package.json +199 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { JsonObject } from "../../json.mjs";
|
|
2
|
+
export declare enum ConversationEntryKind {
|
|
3
|
+
User = "user",
|
|
4
|
+
ToolResult = "tool_result",
|
|
5
|
+
ToolSearchOutput = "tool_search_output"
|
|
6
|
+
}
|
|
7
|
+
export type ConversationEntry = {
|
|
8
|
+
kind: ConversationEntryKind.User;
|
|
9
|
+
text: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: ConversationEntryKind.ToolResult;
|
|
12
|
+
text: string;
|
|
13
|
+
isError: boolean;
|
|
14
|
+
} | {
|
|
15
|
+
kind: ConversationEntryKind.ToolSearchOutput;
|
|
16
|
+
};
|
|
17
|
+
export interface OfferedToolIface {
|
|
18
|
+
name: string;
|
|
19
|
+
namespace: string | null;
|
|
20
|
+
supportsEscalation?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface CodeModeToolIface {
|
|
23
|
+
tool: OfferedToolIface;
|
|
24
|
+
nested: string[];
|
|
25
|
+
}
|
|
26
|
+
export interface ScriptedConversationIface {
|
|
27
|
+
entries: ConversationEntry[];
|
|
28
|
+
tools: OfferedToolIface[];
|
|
29
|
+
toolSearch: boolean;
|
|
30
|
+
codeMode: CodeModeToolIface | null;
|
|
31
|
+
}
|
|
32
|
+
export declare enum ScriptedActionKind {
|
|
33
|
+
Text = "text",
|
|
34
|
+
ToolCall = "tool_call",
|
|
35
|
+
CodeCall = "code_call",
|
|
36
|
+
ToolSearch = "tool_search",
|
|
37
|
+
Slow = "slow",
|
|
38
|
+
Wait = "wait",
|
|
39
|
+
Error = "error"
|
|
40
|
+
}
|
|
41
|
+
export type ScriptedAction = {
|
|
42
|
+
kind: ScriptedActionKind.Text;
|
|
43
|
+
text: string;
|
|
44
|
+
} | {
|
|
45
|
+
kind: ScriptedActionKind.ToolCall;
|
|
46
|
+
tool: OfferedToolIface;
|
|
47
|
+
arguments: JsonObject;
|
|
48
|
+
} | {
|
|
49
|
+
kind: ScriptedActionKind.CodeCall;
|
|
50
|
+
tool: OfferedToolIface;
|
|
51
|
+
source: string;
|
|
52
|
+
} | {
|
|
53
|
+
kind: ScriptedActionKind.ToolSearch;
|
|
54
|
+
query: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: ScriptedActionKind.Slow;
|
|
57
|
+
text: string;
|
|
58
|
+
} | {
|
|
59
|
+
kind: ScriptedActionKind.Wait;
|
|
60
|
+
before: string;
|
|
61
|
+
after: string;
|
|
62
|
+
ms: number;
|
|
63
|
+
} | {
|
|
64
|
+
kind: ScriptedActionKind.Error;
|
|
65
|
+
message: string;
|
|
66
|
+
};
|
|
67
|
+
export interface ReplyPlanIface {
|
|
68
|
+
first: string;
|
|
69
|
+
second: string;
|
|
70
|
+
pauseMs: number;
|
|
71
|
+
held: boolean;
|
|
72
|
+
}
|
|
73
|
+
export declare const replyPlan: (action: ScriptedAction) => ReplyPlanIface | null;
|
|
74
|
+
export declare const PERMISSION_SCRIPT = "printf '%s-%s\\n' conformance permission";
|
|
75
|
+
export declare const PERMISSION_COMMAND = "sh -c \"printf '%s-%s\\n' conformance permission\"";
|
|
76
|
+
export declare const PERMISSION_MARKER = "conformance-permission";
|
|
77
|
+
export declare const SLOW_STARTED_TEXT = "slow:started";
|
|
78
|
+
export declare const SCRIPTED_ERROR_MESSAGE = "scripted provider failure";
|
|
79
|
+
export declare const ELICITATION_UNSUPPORTED_TEXT = "elicitation:unsupported";
|
|
80
|
+
export declare const DEFAULT_WAIT_MS = 500;
|
|
81
|
+
export declare const MAX_WAIT_MS = 120000;
|
|
82
|
+
export declare const qualifiedToolName: (tool: OfferedToolIface) => string;
|
|
83
|
+
export declare const SCRIPTED_RESULT_MARKER = "SCRIPTED_RESULT ";
|
|
84
|
+
export declare const scriptedAction: (conversation: ScriptedConversationIface) => ScriptedAction;
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import {
|
|
3
|
+
CONFORMANCE_ACP_SERVER_NAME,
|
|
4
|
+
CONFORMANCE_BIG_TOOL,
|
|
5
|
+
CONFORMANCE_ELICIT_TOOL,
|
|
6
|
+
CONFORMANCE_HTTP_SERVER_NAME,
|
|
7
|
+
ConformanceDirective,
|
|
8
|
+
parseDirective
|
|
9
|
+
} from "../protocol.mjs";
|
|
10
|
+
var ConversationEntryKind = /* @__PURE__ */ ((ConversationEntryKind2) => {
|
|
11
|
+
ConversationEntryKind2["User"] = "user";
|
|
12
|
+
ConversationEntryKind2["ToolResult"] = "tool_result";
|
|
13
|
+
ConversationEntryKind2["ToolSearchOutput"] = "tool_search_output";
|
|
14
|
+
return ConversationEntryKind2;
|
|
15
|
+
})(ConversationEntryKind || {});
|
|
16
|
+
var ScriptedActionKind = /* @__PURE__ */ ((ScriptedActionKind2) => {
|
|
17
|
+
ScriptedActionKind2["Text"] = "text";
|
|
18
|
+
ScriptedActionKind2["ToolCall"] = "tool_call";
|
|
19
|
+
ScriptedActionKind2["CodeCall"] = "code_call";
|
|
20
|
+
ScriptedActionKind2["ToolSearch"] = "tool_search";
|
|
21
|
+
ScriptedActionKind2["Slow"] = "slow";
|
|
22
|
+
ScriptedActionKind2["Wait"] = "wait";
|
|
23
|
+
ScriptedActionKind2["Error"] = "error";
|
|
24
|
+
return ScriptedActionKind2;
|
|
25
|
+
})(ScriptedActionKind || {});
|
|
26
|
+
const replyPlan = (action) => {
|
|
27
|
+
switch (action.kind) {
|
|
28
|
+
case "text" /* Text */: {
|
|
29
|
+
const half = Math.ceil(action.text.length / 2);
|
|
30
|
+
return {
|
|
31
|
+
first: action.text.slice(0, half),
|
|
32
|
+
second: action.text.slice(half),
|
|
33
|
+
pauseMs: 0,
|
|
34
|
+
held: false
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
case "slow" /* Slow */:
|
|
38
|
+
return { first: action.text, second: "", pauseMs: 0, held: true };
|
|
39
|
+
case "wait" /* Wait */:
|
|
40
|
+
return { first: action.before, second: action.after, pauseMs: action.ms, held: false };
|
|
41
|
+
case "tool_call" /* ToolCall */:
|
|
42
|
+
case "code_call" /* CodeCall */:
|
|
43
|
+
case "tool_search" /* ToolSearch */:
|
|
44
|
+
case "error" /* Error */:
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const PERMISSION_SCRIPT = "printf '%s-%s\\n' conformance permission";
|
|
49
|
+
const PERMISSION_COMMAND = `sh -c "${PERMISSION_SCRIPT}"`;
|
|
50
|
+
const PERMISSION_MARKER = "conformance-permission";
|
|
51
|
+
const SLOW_STARTED_TEXT = "slow:started";
|
|
52
|
+
const SCRIPTED_ERROR_MESSAGE = "scripted provider failure";
|
|
53
|
+
const ELICITATION_UNSUPPORTED_TEXT = "elicitation:unsupported";
|
|
54
|
+
const DEFAULT_WAIT_MS = 500;
|
|
55
|
+
const MAX_WAIT_MS = 12e4;
|
|
56
|
+
const SHELL_TOOLS = [
|
|
57
|
+
{ name: "bash", arguments: { command: PERMISSION_COMMAND } },
|
|
58
|
+
{ name: "Bash", arguments: { command: PERMISSION_COMMAND } },
|
|
59
|
+
{ name: "exec_command", arguments: { cmd: PERMISSION_COMMAND } },
|
|
60
|
+
{ name: "shell_command", arguments: { command: PERMISSION_COMMAND } },
|
|
61
|
+
{ name: "shell", arguments: { command: ["sh", "-c", PERMISSION_SCRIPT] } }
|
|
62
|
+
];
|
|
63
|
+
const text = (value) => ({ kind: "text" /* Text */, text: value });
|
|
64
|
+
const directiveIn = (value) => {
|
|
65
|
+
for (const line of value.split("\n")) {
|
|
66
|
+
const parsed = parseDirective(line);
|
|
67
|
+
if (parsed != null) return parsed;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
};
|
|
71
|
+
const currentDirective = (entries) => {
|
|
72
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
73
|
+
const entry = entries[index];
|
|
74
|
+
if (entry?.kind !== "user" /* User */) continue;
|
|
75
|
+
const parsed = directiveIn(entry.text);
|
|
76
|
+
if (parsed != null) return { ...parsed, after: entries.slice(index + 1) };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
};
|
|
80
|
+
const lastToolResult = (entries) => {
|
|
81
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
82
|
+
const entry = entries[index];
|
|
83
|
+
if (entry?.kind === "tool_result" /* ToolResult */) return entry;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
};
|
|
87
|
+
const toolKey = (value) => value.replace(/[^A-Za-z0-9_]/g, "_");
|
|
88
|
+
const qualifiedToolName = (tool) => {
|
|
89
|
+
if (tool.namespace == null) return tool.name;
|
|
90
|
+
return tool.namespace.endsWith("__") ? `${tool.namespace}${tool.name}` : `${tool.namespace}__${tool.name}`;
|
|
91
|
+
};
|
|
92
|
+
const isMcpToolName = (qualified, server, tool) => {
|
|
93
|
+
const suffix = `${toolKey(server)}__${toolKey(tool)}`;
|
|
94
|
+
const piServer = [...new TextEncoder().encode(server)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
95
|
+
const piSuffix = `final_${piServer}__${toolKey(tool)}`;
|
|
96
|
+
const encodedTool = [...new TextEncoder().encode(tool)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
97
|
+
const adapterSuffix = `final_${piServer}__${encodedTool}`;
|
|
98
|
+
const name = toolKey(qualified);
|
|
99
|
+
return name === suffix || name.endsWith(`_${suffix}`) || name.endsWith(`_${piSuffix}`) || name === adapterSuffix || name.endsWith(`_${adapterSuffix}`);
|
|
100
|
+
};
|
|
101
|
+
const findMcpTool = (tools, server, tool) => tools.find((candidate) => isMcpToolName(qualifiedToolName(candidate), server, tool)) ?? null;
|
|
102
|
+
const SCRIPTED_RESULT_MARKER = "SCRIPTED_RESULT ";
|
|
103
|
+
const nestedCallSource = (args) => [
|
|
104
|
+
"const textOf = (value) => {",
|
|
105
|
+
" if (typeof value === 'string') return value;",
|
|
106
|
+
" const items = Array.isArray(value?.content) ? value.content : Array.isArray(value?.contentItems) ? value.contentItems : null;",
|
|
107
|
+
" if (items == null) return typeof value?.output === 'string' ? value.output : JSON.stringify(value);",
|
|
108
|
+
" return items.filter((item) => typeof item?.text === 'string').map((item) => item.text).join('\\n');",
|
|
109
|
+
"};",
|
|
110
|
+
"let outcome;",
|
|
111
|
+
"try {",
|
|
112
|
+
` const value = await tools.${args.name}(${JSON.stringify(args.input)});`,
|
|
113
|
+
` const text = textOf(value);`,
|
|
114
|
+
` outcome = { isError: value?.isError === true || value?.success === false, text: ${args.summarize ? "String(text.length)" : "text"} };`,
|
|
115
|
+
"} catch (error) {",
|
|
116
|
+
" outcome = { isError: true, text: String(error?.message ?? error) };",
|
|
117
|
+
"}",
|
|
118
|
+
`text(${JSON.stringify(SCRIPTED_RESULT_MARKER)} + JSON.stringify(outcome));`
|
|
119
|
+
].join("\n");
|
|
120
|
+
const codeCallFor = (args) => {
|
|
121
|
+
const codeMode = args.conversation.codeMode;
|
|
122
|
+
const name = codeMode?.nested.find(args.matches);
|
|
123
|
+
if (codeMode == null || name == null) return null;
|
|
124
|
+
return {
|
|
125
|
+
kind: "code_call" /* CodeCall */,
|
|
126
|
+
tool: codeMode.tool,
|
|
127
|
+
source: nestedCallSource({ name, input: args.input, summarize: args.summarize === true })
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
const scriptedOutcomeSchema = z.object({ isError: z.boolean(), text: z.string() });
|
|
131
|
+
const unwrapCodeResult = (result) => {
|
|
132
|
+
const at = result.text.lastIndexOf(SCRIPTED_RESULT_MARKER);
|
|
133
|
+
if (at < 0) return result;
|
|
134
|
+
const line = result.text.slice(at + SCRIPTED_RESULT_MARKER.length).split("\n")[0] ?? "";
|
|
135
|
+
try {
|
|
136
|
+
const outcome = scriptedOutcomeSchema.safeParse(JSON.parse(line));
|
|
137
|
+
return outcome.success ? { ...result, ...outcome.data } : result;
|
|
138
|
+
} catch {
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const mcpArgumentsSchema = z.record(z.string(), z.json());
|
|
143
|
+
const parseMcpArguments = (value) => {
|
|
144
|
+
if (value.trim() === "") return {};
|
|
145
|
+
try {
|
|
146
|
+
const parsed = mcpArgumentsSchema.safeParse(JSON.parse(value));
|
|
147
|
+
return parsed.success ? parsed.data : null;
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
const permissionReply = (result) => {
|
|
153
|
+
if (result.includes(PERMISSION_MARKER)) return "permission:allow_once";
|
|
154
|
+
if (/cancel|interrupt|abort|stopped/i.test(result)) return "permission:cancelled";
|
|
155
|
+
return "permission:reject_once";
|
|
156
|
+
};
|
|
157
|
+
const historyReply = (entries) => entries.flatMap((entry) => entry.kind === "user" /* User */ ? entry.text.split("\n") : []).map((line) => line.trim()).filter((line) => line !== "" && parseDirective(line)?.name !== ConformanceDirective.History).join("\n");
|
|
158
|
+
const scriptedAction = (conversation) => {
|
|
159
|
+
const latestUser = conversation.entries.findLast(
|
|
160
|
+
(entry) => entry.kind === "user" /* User */
|
|
161
|
+
);
|
|
162
|
+
if (latestUser?.kind === "user" /* User */ && latestUser.text.startsWith(
|
|
163
|
+
"CRITICAL: Respond with TEXT ONLY. Do NOT call any tools. Summarize the conversation so far,"
|
|
164
|
+
)) {
|
|
165
|
+
const active = conversation.entries.slice(0, -1).findLast(
|
|
166
|
+
(entry) => entry.kind === "user" /* User */ && directiveIn(entry.text) != null
|
|
167
|
+
);
|
|
168
|
+
return text(
|
|
169
|
+
active?.kind === "user" /* User */ ? active.text : "Conversation summary."
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const current = currentDirective(conversation.entries);
|
|
173
|
+
if (current == null) return text("ok");
|
|
174
|
+
const auxiliary = conversation.tools.length === 0 && !conversation.toolSearch;
|
|
175
|
+
const raw = lastToolResult(current.after);
|
|
176
|
+
const result = raw == null ? null : unwrapCodeResult(raw);
|
|
177
|
+
switch (current.name) {
|
|
178
|
+
case ConformanceDirective.Echo:
|
|
179
|
+
return text(current.rest);
|
|
180
|
+
case ConformanceDirective.Permission: {
|
|
181
|
+
if (result != null) return text(permissionReply(result.text));
|
|
182
|
+
const shell = SHELL_TOOLS.find(
|
|
183
|
+
(candidate) => conversation.tools.some((tool) => tool.namespace == null && tool.name === candidate.name)
|
|
184
|
+
);
|
|
185
|
+
if (shell == null) {
|
|
186
|
+
const nested = codeCallFor({
|
|
187
|
+
conversation,
|
|
188
|
+
matches: (name) => name === "exec_command",
|
|
189
|
+
input: { cmd: PERMISSION_COMMAND }
|
|
190
|
+
});
|
|
191
|
+
return nested ?? text("permission:no-shell-tool");
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
kind: "tool_call" /* ToolCall */,
|
|
195
|
+
tool: { name: shell.name, namespace: null },
|
|
196
|
+
arguments: conversation.tools.some(
|
|
197
|
+
(tool) => tool.name === shell.name && tool.namespace == null && tool.supportsEscalation === true
|
|
198
|
+
) ? {
|
|
199
|
+
...shell.arguments,
|
|
200
|
+
sandbox_permissions: "require_escalated",
|
|
201
|
+
justification: "Approve the conformance permission probe?"
|
|
202
|
+
} : shell.arguments
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
case ConformanceDirective.Mcp: {
|
|
206
|
+
if (result != null) {
|
|
207
|
+
return text(
|
|
208
|
+
result.isError ? `mcp-error:${result.text.trim()}` : `mcp:${result.text.trim()}`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
const [server = "", tool = "", ...json] = current.rest.split(" ");
|
|
212
|
+
const args = parseMcpArguments(json.join(" "));
|
|
213
|
+
if (args == null) return text(`mcp-error:invalid arguments for ${server}/${tool}`);
|
|
214
|
+
const found = findMcpTool(conversation.tools, server, tool);
|
|
215
|
+
if (found != null) return { kind: "tool_call" /* ToolCall */, tool: found, arguments: args };
|
|
216
|
+
const nested = codeCallFor({
|
|
217
|
+
conversation,
|
|
218
|
+
matches: (name) => isMcpToolName(name, server, tool),
|
|
219
|
+
input: args
|
|
220
|
+
});
|
|
221
|
+
if (nested != null) return nested;
|
|
222
|
+
const searched = current.after.some(
|
|
223
|
+
(entry) => entry.kind === "tool_search_output" /* ToolSearchOutput */
|
|
224
|
+
);
|
|
225
|
+
if (conversation.toolSearch && !searched) {
|
|
226
|
+
return { kind: "tool_search" /* ToolSearch */, query: `${server} ${tool}` };
|
|
227
|
+
}
|
|
228
|
+
return text(`mcp-error:no tool ${server}/${tool}`);
|
|
229
|
+
}
|
|
230
|
+
case ConformanceDirective.History:
|
|
231
|
+
return text(historyReply(conversation.entries));
|
|
232
|
+
case ConformanceDirective.Slow:
|
|
233
|
+
return auxiliary ? text(SLOW_STARTED_TEXT) : { kind: "slow" /* Slow */, text: SLOW_STARTED_TEXT };
|
|
234
|
+
case ConformanceDirective.Error:
|
|
235
|
+
return { kind: "error" /* Error */, message: SCRIPTED_ERROR_MESSAGE };
|
|
236
|
+
case ConformanceDirective.Wait: {
|
|
237
|
+
const ms = Number.parseInt(current.rest, 10);
|
|
238
|
+
return {
|
|
239
|
+
kind: "wait" /* Wait */,
|
|
240
|
+
before: "wait:started",
|
|
241
|
+
after: "wait:done",
|
|
242
|
+
ms: Number.isFinite(ms) && ms >= 0 ? Math.min(ms, MAX_WAIT_MS) : DEFAULT_WAIT_MS
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
case ConformanceDirective.Elicit: {
|
|
246
|
+
if (result != null) return text(result.text.trim());
|
|
247
|
+
const tool = findMcpTool(
|
|
248
|
+
conversation.tools,
|
|
249
|
+
CONFORMANCE_HTTP_SERVER_NAME,
|
|
250
|
+
CONFORMANCE_ELICIT_TOOL
|
|
251
|
+
);
|
|
252
|
+
if (tool != null) return { kind: "tool_call" /* ToolCall */, tool, arguments: {} };
|
|
253
|
+
const nested = codeCallFor({
|
|
254
|
+
conversation,
|
|
255
|
+
matches: (name) => isMcpToolName(name, CONFORMANCE_HTTP_SERVER_NAME, CONFORMANCE_ELICIT_TOOL),
|
|
256
|
+
input: {}
|
|
257
|
+
});
|
|
258
|
+
if (nested != null) return nested;
|
|
259
|
+
if (conversation.toolSearch && !current.after.some((entry) => entry.kind === "tool_search_output" /* ToolSearchOutput */))
|
|
260
|
+
return {
|
|
261
|
+
kind: "tool_search" /* ToolSearch */,
|
|
262
|
+
query: `${CONFORMANCE_HTTP_SERVER_NAME} ${CONFORMANCE_ELICIT_TOOL}`
|
|
263
|
+
};
|
|
264
|
+
return text(ELICITATION_UNSUPPORTED_TEXT);
|
|
265
|
+
}
|
|
266
|
+
case ConformanceDirective.Clear:
|
|
267
|
+
return text("clear:unsupported");
|
|
268
|
+
case ConformanceDirective.Big: {
|
|
269
|
+
if (result != null) return text(result.isError ? "big:failed" : "big:done");
|
|
270
|
+
const tool = findMcpTool(conversation.tools, CONFORMANCE_ACP_SERVER_NAME, CONFORMANCE_BIG_TOOL) ?? findMcpTool(conversation.tools, CONFORMANCE_HTTP_SERVER_NAME, CONFORMANCE_BIG_TOOL);
|
|
271
|
+
const bytes = Number.parseInt(current.rest, 10);
|
|
272
|
+
if (tool != null) return { kind: "tool_call" /* ToolCall */, tool, arguments: { bytes } };
|
|
273
|
+
const nested = codeCallFor({
|
|
274
|
+
conversation,
|
|
275
|
+
matches: (name) => isMcpToolName(name, CONFORMANCE_ACP_SERVER_NAME, CONFORMANCE_BIG_TOOL),
|
|
276
|
+
input: { bytes },
|
|
277
|
+
summarize: true
|
|
278
|
+
}) ?? codeCallFor({
|
|
279
|
+
conversation,
|
|
280
|
+
matches: (name) => isMcpToolName(name, CONFORMANCE_HTTP_SERVER_NAME, CONFORMANCE_BIG_TOOL),
|
|
281
|
+
input: { bytes },
|
|
282
|
+
summarize: true
|
|
283
|
+
});
|
|
284
|
+
return nested ?? text("big:no-tool");
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
export {
|
|
289
|
+
ConversationEntryKind,
|
|
290
|
+
DEFAULT_WAIT_MS,
|
|
291
|
+
ELICITATION_UNSUPPORTED_TEXT,
|
|
292
|
+
MAX_WAIT_MS,
|
|
293
|
+
PERMISSION_COMMAND,
|
|
294
|
+
PERMISSION_MARKER,
|
|
295
|
+
PERMISSION_SCRIPT,
|
|
296
|
+
SCRIPTED_ERROR_MESSAGE,
|
|
297
|
+
SCRIPTED_RESULT_MARKER,
|
|
298
|
+
SLOW_STARTED_TEXT,
|
|
299
|
+
ScriptedActionKind,
|
|
300
|
+
qualifiedToolName,
|
|
301
|
+
replyPlan,
|
|
302
|
+
scriptedAction
|
|
303
|
+
};
|
|
304
|
+
//# sourceMappingURL=directives.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/conformance/scripted-model/directives.ts"],
|
|
4
|
+
"sourcesContent": ["import * as z from 'zod';\nimport type { JsonObject } from \"../../json.mjs\";\nimport {\n CONFORMANCE_ACP_SERVER_NAME,\n CONFORMANCE_BIG_TOOL,\n CONFORMANCE_ELICIT_TOOL,\n CONFORMANCE_HTTP_SERVER_NAME,\n ConformanceDirective,\n parseDirective,\n} from \"../protocol.mjs\";\n\n// What the scripted conformance model does for one model request, decided from\n// the request alone (no state between requests, so any replica answers alike).\n// Each wire module (chat-completions.ts, responses.ts, messages.ts) turns its\n// request into a ScriptedConversationIface and encodes the action back.\n//\n// The model follows the kit's directives (protocol.ts) the way an LLM would,\n// through the harness's own tools:\n// - echo: replies the text;\n// - permission: runs PERMISSION_COMMAND with the harness's native shell tool\n// (the harness must be in a mode that asks before it), then reports the\n// decision its result shows;\n// - mcp: calls `<server>`'s `<tool>` under the harness's MCP tool naming\n// (searching for it first when the harness defers tools behind tool_search),\n// then replies with its result;\n// - history: replies every user line it was sent;\n// - slow: streams `slow:started` and holds the response open until aborted;\n// - error: fails the request with a non-retryable provider error;\n// - wait: streams `wait:started`, pauses, streams `wait:done` in one reply;\n// - big: calls the kit's large-result MCP tool, then replies big:done;\n// - elicit: calls the HTTP fixture's tool, which asks through MCP input_required;\n// - clear: a model cannot reset a harness's native conversation.\n//\n// A harness can offer its tools nested inside one code tool instead (Codex's code mode, for\n// models such as gpt-6-sol: a freeform `exec` tool running JavaScript that calls\n// `tools.<name>(...)`). The model then calls a tool by writing that code, which reports the\n// nested call's outcome on a SCRIPTED_RESULT line.\n\nexport enum ConversationEntryKind {\n User = 'user',\n ToolResult = 'tool_result',\n ToolSearchOutput = 'tool_search_output',\n}\n\nexport type ConversationEntry =\n | { kind: ConversationEntryKind.User; text: string }\n | { kind: ConversationEntryKind.ToolResult; text: string; isError: boolean }\n | { kind: ConversationEntryKind.ToolSearchOutput };\n\n// A tool the request offers; Responses namespaces keep their namespace.\nexport interface OfferedToolIface {\n name: string;\n namespace: string | null;\n // Native Codex advertises escalation; managed sandbox tools do not.\n supportsEscalation?: boolean;\n}\n\n// A code tool and the nested tools its code can call by name.\nexport interface CodeModeToolIface {\n tool: OfferedToolIface;\n nested: string[];\n}\n\nexport interface ScriptedConversationIface {\n // User texts, tool results and tool search outputs in request order.\n entries: ConversationEntry[];\n tools: OfferedToolIface[];\n // A client-executed `tool_search` is offered (Codex defers tools behind it).\n toolSearch: boolean;\n codeMode: CodeModeToolIface | null;\n}\n\nexport enum ScriptedActionKind {\n Text = 'text',\n ToolCall = 'tool_call',\n CodeCall = 'code_call',\n ToolSearch = 'tool_search',\n Slow = 'slow',\n Wait = 'wait',\n Error = 'error',\n}\n\nexport type ScriptedAction =\n | { kind: ScriptedActionKind.Text; text: string }\n | { kind: ScriptedActionKind.ToolCall; tool: OfferedToolIface; arguments: JsonObject }\n // A freeform call of a code tool with `source` as its whole input.\n | { kind: ScriptedActionKind.CodeCall; tool: OfferedToolIface; source: string }\n | { kind: ScriptedActionKind.ToolSearch; query: string }\n | { kind: ScriptedActionKind.Slow; text: string }\n | { kind: ScriptedActionKind.Wait; before: string; after: string; ms: number }\n | { kind: ScriptedActionKind.Error; message: string };\n\n// How a text-like action streams: `first`, then (after `pauseMs`, or never\n// when held) `second` and the end of the response.\nexport interface ReplyPlanIface {\n first: string;\n second: string;\n pauseMs: number;\n held: boolean;\n}\n\nexport const replyPlan = (action: ScriptedAction): ReplyPlanIface | null => {\n switch (action.kind) {\n case ScriptedActionKind.Text: {\n // Two deltas, so the reply streams.\n const half = Math.ceil(action.text.length / 2);\n return {\n first: action.text.slice(0, half),\n second: action.text.slice(half),\n pauseMs: 0,\n held: false,\n };\n }\n case ScriptedActionKind.Slow:\n return { first: action.text, second: '', pauseMs: 0, held: true };\n case ScriptedActionKind.Wait:\n return { first: action.before, second: action.after, pauseMs: action.ms, held: false };\n case ScriptedActionKind.ToolCall:\n case ScriptedActionKind.CodeCall:\n case ScriptedActionKind.ToolSearch:\n case ScriptedActionKind.Error:\n return null;\n }\n};\n\n// Prints PERMISSION_MARKER only when it runs: the marker is not a substring of\n// the command, so a refusal that quotes the command is not taken for a run.\n// Codex requires an explicit escalation: a harmless command can run inside its sandbox.\nexport const PERMISSION_SCRIPT = \"printf '%s-%s\\\\n' conformance permission\";\nexport const PERMISSION_COMMAND = `sh -c \"${PERMISSION_SCRIPT}\"`;\nexport const PERMISSION_MARKER = 'conformance-permission';\nexport const SLOW_STARTED_TEXT = 'slow:started';\nexport const SCRIPTED_ERROR_MESSAGE = 'scripted provider failure';\nexport const ELICITATION_UNSUPPORTED_TEXT = 'elicitation:unsupported';\nexport const DEFAULT_WAIT_MS = 500;\n// Bounds a scripted wait so a request cannot hold the endpoint indefinitely.\nexport const MAX_WAIT_MS = 120_000;\n\n// Native shell tools by name, with the arguments each takes: Pi's `bash`,\n// Claude Code's `Bash`, Codex's `exec_command` (and its older `shell_command`\n// and `shell`).\nconst SHELL_TOOLS: readonly { name: string; arguments: JsonObject }[] = [\n { name: 'bash', arguments: { command: PERMISSION_COMMAND } },\n { name: 'Bash', arguments: { command: PERMISSION_COMMAND } },\n { name: 'exec_command', arguments: { cmd: PERMISSION_COMMAND } },\n { name: 'shell_command', arguments: { command: PERMISSION_COMMAND } },\n { name: 'shell', arguments: { command: ['sh', '-c', PERMISSION_SCRIPT] } },\n];\n\nconst text = (value: string): ScriptedAction => ({ kind: ScriptedActionKind.Text, text: value });\n\nconst directiveIn = (value: string): ReturnType<typeof parseDirective> => {\n for (const line of value.split('\\n')) {\n const parsed = parseDirective(line);\n if (parsed != null) return parsed;\n }\n return null;\n};\n\ninterface CurrentDirectiveIface {\n name: ConformanceDirective;\n rest: string;\n // Entries after the prompt that carried it (this turn's tool round trips).\n after: ConversationEntry[];\n}\n\n// The latest prompt carrying a directive is the turn being answered; harness\n// wrappers (environment context, reminders) never carry one.\nconst currentDirective = (entries: ConversationEntry[]): CurrentDirectiveIface | null => {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.kind !== ConversationEntryKind.User) continue;\n const parsed = directiveIn(entry.text);\n if (parsed != null) return { ...parsed, after: entries.slice(index + 1) };\n }\n return null;\n};\n\nconst lastToolResult = (\n entries: ConversationEntry[],\n): Extract<ConversationEntry, { kind: ConversationEntryKind.ToolResult }> | null => {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index];\n if (entry?.kind === ConversationEntryKind.ToolResult) return entry;\n }\n return null;\n};\n\nconst toolKey = (value: string): string => value.replace(/[^A-Za-z0-9_]/g, '_');\n\n// The tool's model-visible name, namespace included (`mcp__srv__` + `echo`).\nexport const qualifiedToolName = (tool: OfferedToolIface): string => {\n if (tool.namespace == null) return tool.name;\n return tool.namespace.endsWith('__')\n ? `${tool.namespace}${tool.name}`\n : `${tool.namespace}__${tool.name}`;\n};\n\n// MCP tools are `<server>__<tool>` with a harness prefix (`mcp__` for nanocode,\n// Claude Code and Codex). Pi's adapter hex-encodes the server namespace to\n// avoid collisions in Pi's restricted server names.\nconst isMcpToolName = (qualified: string, server: string, tool: string): boolean => {\n const suffix = `${toolKey(server)}__${toolKey(tool)}`;\n const piServer = [...new TextEncoder().encode(server)]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n const piSuffix = `final_${piServer}__${toolKey(tool)}`;\n const encodedTool = [...new TextEncoder().encode(tool)]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n const adapterSuffix = `final_${piServer}__${encodedTool}`;\n const name = toolKey(qualified);\n return (\n name === suffix ||\n name.endsWith(`_${suffix}`) ||\n name.endsWith(`_${piSuffix}`) ||\n name === adapterSuffix ||\n name.endsWith(`_${adapterSuffix}`)\n );\n};\n\nconst findMcpTool = (\n tools: OfferedToolIface[],\n server: string,\n tool: string,\n): OfferedToolIface | null =>\n tools.find((candidate) => isMcpToolName(qualifiedToolName(candidate), server, tool)) ?? null;\n\n// The outcome line the code below prints; its JSON is `{ isError, text }`.\nexport const SCRIPTED_RESULT_MARKER = 'SCRIPTED_RESULT ';\n\n// Code calling one nested tool and printing its outcome, text content only (a large result's\n// text is reduced to its length so it never returns to the model).\nconst nestedCallSource = (args: { name: string; input: JsonObject; summarize: boolean }) =>\n [\n 'const textOf = (value) => {',\n \" if (typeof value === 'string') return value;\",\n ' const items = Array.isArray(value?.content) ? value.content : Array.isArray(value?.contentItems) ? value.contentItems : null;',\n \" if (items == null) return typeof value?.output === 'string' ? value.output : JSON.stringify(value);\",\n \" return items.filter((item) => typeof item?.text === 'string').map((item) => item.text).join('\\\\n');\",\n '};',\n 'let outcome;',\n 'try {',\n ` const value = await tools.${args.name}(${JSON.stringify(args.input)});`,\n ` const text = textOf(value);`,\n ` outcome = { isError: value?.isError === true || value?.success === false, text: ${args.summarize ? 'String(text.length)' : 'text'} };`,\n '} catch (error) {',\n ' outcome = { isError: true, text: String(error?.message ?? error) };',\n '}',\n `text(${JSON.stringify(SCRIPTED_RESULT_MARKER)} + JSON.stringify(outcome));`,\n ].join('\\n');\n\n// The nested tool a code tool offers for an MCP server's tool, as a call of that code tool.\nconst codeCallFor = (args: {\n conversation: ScriptedConversationIface;\n matches: (name: string) => boolean;\n input: JsonObject;\n summarize?: boolean;\n}): ScriptedAction | null => {\n const codeMode = args.conversation.codeMode;\n const name = codeMode?.nested.find(args.matches);\n if (codeMode == null || name == null) return null;\n return {\n kind: ScriptedActionKind.CodeCall,\n tool: codeMode.tool,\n source: nestedCallSource({ name, input: args.input, summarize: args.summarize === true }),\n };\n};\n\nconst scriptedOutcomeSchema = z.object({ isError: z.boolean(), text: z.string() });\n\n// A code tool's output carries the nested call's outcome on its marker line.\nconst unwrapCodeResult = (\n result: Extract<ConversationEntry, { kind: ConversationEntryKind.ToolResult }>,\n): Extract<ConversationEntry, { kind: ConversationEntryKind.ToolResult }> => {\n const at = result.text.lastIndexOf(SCRIPTED_RESULT_MARKER);\n if (at < 0) return result;\n const line = result.text.slice(at + SCRIPTED_RESULT_MARKER.length).split('\\n')[0] ?? '';\n try {\n const outcome = scriptedOutcomeSchema.safeParse(JSON.parse(line));\n return outcome.success ? { ...result, ...outcome.data } : result;\n } catch {\n return result;\n }\n};\n\nconst mcpArgumentsSchema = z.record(z.string(), z.json());\n\nconst parseMcpArguments = (value: string): JsonObject | null => {\n if (value.trim() === '') return {};\n try {\n const parsed = mcpArgumentsSchema.safeParse(JSON.parse(value));\n return parsed.success ? parsed.data : null;\n } catch {\n return null;\n }\n};\n\nconst permissionReply = (result: string): string => {\n if (result.includes(PERMISSION_MARKER)) return 'permission:allow_once';\n if (/cancel|interrupt|abort|stopped/i.test(result)) return 'permission:cancelled';\n return 'permission:reject_once';\n};\n\nconst historyReply = (entries: ConversationEntry[]): string =>\n entries\n .flatMap((entry) => (entry.kind === ConversationEntryKind.User ? entry.text.split('\\n') : []))\n .map((line) => line.trim())\n .filter((line) => line !== '' && parseDirective(line)?.name !== ConformanceDirective.History)\n .join('\\n');\n\nexport const scriptedAction = (conversation: ScriptedConversationIface): ScriptedAction => {\n const latestUser = conversation.entries.findLast(\n (entry) => entry.kind === ConversationEntryKind.User,\n );\n if (\n latestUser?.kind === ConversationEntryKind.User &&\n latestUser.text.startsWith(\n 'CRITICAL: Respond with TEXT ONLY. Do NOT call any tools. Summarize the conversation so far,',\n )\n ) {\n const active = conversation.entries\n .slice(0, -1)\n .findLast(\n (entry) => entry.kind === ConversationEntryKind.User && directiveIn(entry.text) != null,\n );\n return text(\n active?.kind === ConversationEntryKind.User ? active.text : 'Conversation summary.',\n );\n }\n const current = currentDirective(conversation.entries);\n if (current == null) return text('ok');\n // A request offering no tools is auxiliary (a session title, a topic check):\n // it gets text, so it never holds the turn or calls a tool it was not given.\n const auxiliary = conversation.tools.length === 0 && !conversation.toolSearch;\n const raw = lastToolResult(current.after);\n const result = raw == null ? null : unwrapCodeResult(raw);\n switch (current.name) {\n case ConformanceDirective.Echo:\n return text(current.rest);\n case ConformanceDirective.Permission: {\n if (result != null) return text(permissionReply(result.text));\n const shell = SHELL_TOOLS.find((candidate) =>\n conversation.tools.some((tool) => tool.namespace == null && tool.name === candidate.name),\n );\n if (shell == null) {\n const nested = codeCallFor({\n conversation,\n matches: (name) => name === 'exec_command',\n input: { cmd: PERMISSION_COMMAND },\n });\n return nested ?? text('permission:no-shell-tool');\n }\n return {\n kind: ScriptedActionKind.ToolCall,\n tool: { name: shell.name, namespace: null },\n arguments: conversation.tools.some(\n (tool) =>\n tool.name === shell.name && tool.namespace == null && tool.supportsEscalation === true,\n )\n ? {\n ...shell.arguments,\n sandbox_permissions: 'require_escalated',\n justification: 'Approve the conformance permission probe?',\n }\n : shell.arguments,\n };\n }\n case ConformanceDirective.Mcp: {\n if (result != null) {\n return text(\n result.isError ? `mcp-error:${result.text.trim()}` : `mcp:${result.text.trim()}`,\n );\n }\n const [server = '', tool = '', ...json] = current.rest.split(' ');\n const args = parseMcpArguments(json.join(' '));\n if (args == null) return text(`mcp-error:invalid arguments for ${server}/${tool}`);\n const found = findMcpTool(conversation.tools, server, tool);\n if (found != null) return { kind: ScriptedActionKind.ToolCall, tool: found, arguments: args };\n const nested = codeCallFor({\n conversation,\n matches: (name) => isMcpToolName(name, server, tool),\n input: args,\n });\n if (nested != null) return nested;\n const searched = current.after.some(\n (entry) => entry.kind === ConversationEntryKind.ToolSearchOutput,\n );\n if (conversation.toolSearch && !searched) {\n return { kind: ScriptedActionKind.ToolSearch, query: `${server} ${tool}` };\n }\n return text(`mcp-error:no tool ${server}/${tool}`);\n }\n case ConformanceDirective.History:\n return text(historyReply(conversation.entries));\n case ConformanceDirective.Slow:\n return auxiliary\n ? text(SLOW_STARTED_TEXT)\n : { kind: ScriptedActionKind.Slow, text: SLOW_STARTED_TEXT };\n case ConformanceDirective.Error:\n return { kind: ScriptedActionKind.Error, message: SCRIPTED_ERROR_MESSAGE };\n case ConformanceDirective.Wait: {\n const ms = Number.parseInt(current.rest, 10);\n return {\n kind: ScriptedActionKind.Wait,\n before: 'wait:started',\n after: 'wait:done',\n ms: Number.isFinite(ms) && ms >= 0 ? Math.min(ms, MAX_WAIT_MS) : DEFAULT_WAIT_MS,\n };\n }\n case ConformanceDirective.Elicit: {\n if (result != null) return text(result.text.trim());\n const tool = findMcpTool(\n conversation.tools,\n CONFORMANCE_HTTP_SERVER_NAME,\n CONFORMANCE_ELICIT_TOOL,\n );\n if (tool != null) return { kind: ScriptedActionKind.ToolCall, tool, arguments: {} };\n const nested = codeCallFor({\n conversation,\n matches: (name) =>\n isMcpToolName(name, CONFORMANCE_HTTP_SERVER_NAME, CONFORMANCE_ELICIT_TOOL),\n input: {},\n });\n if (nested != null) return nested;\n if (\n conversation.toolSearch &&\n !current.after.some((entry) => entry.kind === ConversationEntryKind.ToolSearchOutput)\n )\n return {\n kind: ScriptedActionKind.ToolSearch,\n query: `${CONFORMANCE_HTTP_SERVER_NAME} ${CONFORMANCE_ELICIT_TOOL}`,\n };\n return text(ELICITATION_UNSUPPORTED_TEXT);\n }\n case ConformanceDirective.Clear:\n return text('clear:unsupported');\n case ConformanceDirective.Big: {\n if (result != null) return text(result.isError ? 'big:failed' : 'big:done');\n const tool =\n findMcpTool(conversation.tools, CONFORMANCE_ACP_SERVER_NAME, CONFORMANCE_BIG_TOOL) ??\n findMcpTool(conversation.tools, CONFORMANCE_HTTP_SERVER_NAME, CONFORMANCE_BIG_TOOL);\n const bytes = Number.parseInt(current.rest, 10);\n if (tool != null) return { kind: ScriptedActionKind.ToolCall, tool, arguments: { bytes } };\n const nested =\n codeCallFor({\n conversation,\n matches: (name) => isMcpToolName(name, CONFORMANCE_ACP_SERVER_NAME, CONFORMANCE_BIG_TOOL),\n input: { bytes },\n summarize: true,\n }) ??\n codeCallFor({\n conversation,\n matches: (name) =>\n isMcpToolName(name, CONFORMANCE_HTTP_SERVER_NAME, CONFORMANCE_BIG_TOOL),\n input: { bytes },\n summarize: true,\n });\n return nested ?? text('big:no-tool');\n }\n }\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["ConversationEntryKind", "ScriptedActionKind"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type HeldStreamTimingIface } from "./sse.mjs";
|
|
2
|
+
export declare const MAX_REQUEST_BYTES: number;
|
|
3
|
+
export interface ScriptedModelHandlerArgsIface {
|
|
4
|
+
apiKey: string | null;
|
|
5
|
+
timing?: HeldStreamTimingIface;
|
|
6
|
+
}
|
|
7
|
+
export type ScriptedModelHandler = (request: Request) => Promise<Response>;
|
|
8
|
+
export declare enum ModelWire {
|
|
9
|
+
ChatCompletions = "chat-completions",
|
|
10
|
+
Responses = "responses",
|
|
11
|
+
Messages = "messages"
|
|
12
|
+
}
|
|
13
|
+
export declare const wireOfPath: (path: string) => ModelWire | null;
|
|
14
|
+
export declare const createScriptedModelHandler: (args: ScriptedModelHandlerArgsIface) => ScriptedModelHandler;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import {
|
|
3
|
+
chatCompletionsConversation,
|
|
4
|
+
chatCompletionsRequestSchema,
|
|
5
|
+
chatCompletionsResponse
|
|
6
|
+
} from "./chat-completions.mjs";
|
|
7
|
+
import { scriptedAction } from "./directives.mjs";
|
|
8
|
+
import { messagesConversation, messagesRequestSchema, messagesResponse } from "./messages.mjs";
|
|
9
|
+
import { responsesConversation, responsesRequestSchema, responsesResponse } from "./responses.mjs";
|
|
10
|
+
import { DEFAULT_HELD_STREAM_TIMING, jsonResponse } from "./sse.mjs";
|
|
11
|
+
const MAX_REQUEST_BYTES = 4 * 1024 * 1024;
|
|
12
|
+
var ModelWire = /* @__PURE__ */ ((ModelWire2) => {
|
|
13
|
+
ModelWire2["ChatCompletions"] = "chat-completions";
|
|
14
|
+
ModelWire2["Responses"] = "responses";
|
|
15
|
+
ModelWire2["Messages"] = "messages";
|
|
16
|
+
return ModelWire2;
|
|
17
|
+
})(ModelWire || {});
|
|
18
|
+
const wireOfPath = (path) => {
|
|
19
|
+
if (path.endsWith("/chat/completions")) return "chat-completions" /* ChatCompletions */;
|
|
20
|
+
if (path.endsWith("/responses")) return "responses" /* Responses */;
|
|
21
|
+
if (path.endsWith("/messages")) return "messages" /* Messages */;
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
const errorBody = (type, message) => ({ error: { type, message } });
|
|
25
|
+
const presentedKey = (headers) => {
|
|
26
|
+
const apiKey = headers.get("x-api-key");
|
|
27
|
+
if (apiKey != null) return apiKey;
|
|
28
|
+
const match = /^Bearer\s+(\S+)$/i.exec(headers.get("authorization") ?? "");
|
|
29
|
+
return match?.[1] ?? null;
|
|
30
|
+
};
|
|
31
|
+
const sha256 = async (value) => new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)));
|
|
32
|
+
const keyMatches = async (presented, expected) => {
|
|
33
|
+
const [left, right] = await Promise.all([sha256(presented), sha256(expected)]);
|
|
34
|
+
let difference = 0;
|
|
35
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
36
|
+
difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
|
|
37
|
+
}
|
|
38
|
+
return difference === 0;
|
|
39
|
+
};
|
|
40
|
+
const readJson = async (request) => {
|
|
41
|
+
const declared = Number(request.headers.get("content-length") ?? "0");
|
|
42
|
+
if (declared > MAX_REQUEST_BYTES) {
|
|
43
|
+
return jsonResponse(413, errorBody("invalid_request_error", "request too large"));
|
|
44
|
+
}
|
|
45
|
+
let text = "";
|
|
46
|
+
const reader = request.body?.getReader();
|
|
47
|
+
if (reader != null) {
|
|
48
|
+
const decoder = new TextDecoder();
|
|
49
|
+
let bytes = 0;
|
|
50
|
+
try {
|
|
51
|
+
while (true) {
|
|
52
|
+
const chunk = await reader.read();
|
|
53
|
+
if (chunk.done) break;
|
|
54
|
+
bytes += chunk.value.byteLength;
|
|
55
|
+
if (bytes > MAX_REQUEST_BYTES) {
|
|
56
|
+
await reader.cancel();
|
|
57
|
+
return jsonResponse(413, errorBody("invalid_request_error", "request too large"));
|
|
58
|
+
}
|
|
59
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
60
|
+
}
|
|
61
|
+
text += decoder.decode();
|
|
62
|
+
} finally {
|
|
63
|
+
reader.releaseLock();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const value = JSON.parse(text);
|
|
68
|
+
return { value };
|
|
69
|
+
} catch {
|
|
70
|
+
return jsonResponse(400, errorBody("invalid_request_error", "the body is not JSON"));
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const invalid = (error) => jsonResponse(
|
|
74
|
+
400,
|
|
75
|
+
errorBody("invalid_request_error", error.issues[0]?.message ?? "invalid request")
|
|
76
|
+
);
|
|
77
|
+
const createScriptedModelHandler = (args) => {
|
|
78
|
+
const timing = args.timing ?? DEFAULT_HELD_STREAM_TIMING;
|
|
79
|
+
return async (request) => {
|
|
80
|
+
const path = new URL(request.url).pathname.replace(/\/+$/, "");
|
|
81
|
+
if (request.method === "GET" && path === "/healthz") return jsonResponse(200, { ok: true });
|
|
82
|
+
if (args.apiKey == null) {
|
|
83
|
+
return jsonResponse(
|
|
84
|
+
503,
|
|
85
|
+
errorBody("api_error", "the scripted model has no API key configured")
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const presented = presentedKey(request.headers);
|
|
89
|
+
if (presented == null || !await keyMatches(presented, args.apiKey)) {
|
|
90
|
+
return jsonResponse(401, errorBody("authentication_error", "invalid API key"));
|
|
91
|
+
}
|
|
92
|
+
if (request.method === "GET" && path.endsWith("/models")) {
|
|
93
|
+
return jsonResponse(200, { object: "list", data: [] });
|
|
94
|
+
}
|
|
95
|
+
if (request.method !== "POST") {
|
|
96
|
+
return jsonResponse(404, errorBody("not_found_error", `no route ${request.method} ${path}`));
|
|
97
|
+
}
|
|
98
|
+
if (path.endsWith("/messages/count_tokens")) return jsonResponse(200, { input_tokens: 12 });
|
|
99
|
+
const wire = wireOfPath(path);
|
|
100
|
+
if (wire == null) {
|
|
101
|
+
return jsonResponse(404, errorBody("not_found_error", `no route POST ${path}`));
|
|
102
|
+
}
|
|
103
|
+
const body = await readJson(request);
|
|
104
|
+
if (body instanceof Response) return body;
|
|
105
|
+
switch (wire) {
|
|
106
|
+
case "chat-completions" /* ChatCompletions */: {
|
|
107
|
+
const parsed = chatCompletionsRequestSchema.safeParse(body.value);
|
|
108
|
+
if (!parsed.success) return invalid(parsed.error);
|
|
109
|
+
const action = scriptedAction(chatCompletionsConversation(parsed.data));
|
|
110
|
+
return chatCompletionsResponse({ request: parsed.data, action, timing });
|
|
111
|
+
}
|
|
112
|
+
case "responses" /* Responses */: {
|
|
113
|
+
const parsed = responsesRequestSchema.safeParse(body.value);
|
|
114
|
+
if (!parsed.success) return invalid(parsed.error);
|
|
115
|
+
const action = scriptedAction(responsesConversation(parsed.data));
|
|
116
|
+
return responsesResponse({ request: parsed.data, action, timing });
|
|
117
|
+
}
|
|
118
|
+
case "messages" /* Messages */: {
|
|
119
|
+
const parsed = messagesRequestSchema.safeParse(body.value);
|
|
120
|
+
if (!parsed.success) return invalid(parsed.error);
|
|
121
|
+
const action = scriptedAction(messagesConversation(parsed.data));
|
|
122
|
+
return messagesResponse({ request: parsed.data, action, timing });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
export {
|
|
128
|
+
MAX_REQUEST_BYTES,
|
|
129
|
+
ModelWire,
|
|
130
|
+
createScriptedModelHandler,
|
|
131
|
+
wireOfPath
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=handler.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/conformance/scripted-model/handler.ts"],
|
|
4
|
+
"sourcesContent": ["import * as z from 'zod';\nimport {\n chatCompletionsConversation,\n chatCompletionsRequestSchema,\n chatCompletionsResponse,\n} from \"./chat-completions.mjs\";\nimport { scriptedAction } from \"./directives.mjs\";\nimport { messagesConversation, messagesRequestSchema, messagesResponse } from \"./messages.mjs\";\nimport { responsesConversation, responsesRequestSchema, responsesResponse } from \"./responses.mjs\";\nimport { DEFAULT_HELD_STREAM_TIMING, jsonResponse, type HeldStreamTimingIface } from \"./sse.mjs\";\n\n// The scripted conformance model as a fetch handler: an ordinary model endpoint\n// a definition reaches through `credentials.apiKey({ secret, baseUrl })`, for\n// every wire the harnesses use, routed by path like a vendor API:\n// POST \u2026/chat/completions OpenAI / OpenRouter chat completions (Pi)\n// POST \u2026/responses OpenAI Responses, incl. Responses Lite (Codex)\n// POST \u2026/messages Anthropic Messages (Claude Code, nanocode Claude)\n// POST \u2026/messages/count_tokens Anthropic token counting\n// GET \u2026/models an empty model list\n// GET /healthz unauthenticated liveness, nothing else\n// Every other route needs the configured key as a bearer token or `x-api-key`\n// (Anthropic): this is not an open model endpoint. Without a key it refuses all.\n\n// Conformance conversations are short; anything larger is not a harness under test.\nexport const MAX_REQUEST_BYTES = 4 * 1024 * 1024;\n\nexport interface ScriptedModelHandlerArgsIface {\n // Null: not configured, every model route refuses.\n apiKey: string | null;\n timing?: HeldStreamTimingIface;\n}\n\nexport type ScriptedModelHandler = (request: Request) => Promise<Response>;\n\nexport enum ModelWire {\n ChatCompletions = 'chat-completions',\n Responses = 'responses',\n Messages = 'messages',\n}\n\nexport const wireOfPath = (path: string): ModelWire | null => {\n if (path.endsWith('/chat/completions')) return ModelWire.ChatCompletions;\n if (path.endsWith('/responses')) return ModelWire.Responses;\n if (path.endsWith('/messages')) return ModelWire.Messages;\n return null;\n};\n\nconst errorBody = (type: string, message: string) => ({ error: { type, message } });\n\nconst presentedKey = (headers: Headers): string | null => {\n const apiKey = headers.get('x-api-key');\n if (apiKey != null) return apiKey;\n const match = /^Bearer\\s+(\\S+)$/i.exec(headers.get('authorization') ?? '');\n return match?.[1] ?? null;\n};\n\nconst sha256 = async (value: string): Promise<Uint8Array> =>\n new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value)));\n\n// Compares digests, so the time taken says nothing about the key.\nconst keyMatches = async (presented: string, expected: string): Promise<boolean> => {\n const [left, right] = await Promise.all([sha256(presented), sha256(expected)]);\n let difference = 0;\n for (let index = 0; index < left.length; index += 1) {\n difference |= (left[index] ?? 0) ^ (right[index] ?? 0);\n }\n return difference === 0;\n};\n\nconst readJson = async (request: Request): Promise<{ value: unknown } | Response> => {\n const declared = Number(request.headers.get('content-length') ?? '0');\n if (declared > MAX_REQUEST_BYTES) {\n return jsonResponse(413, errorBody('invalid_request_error', 'request too large'));\n }\n let text = '';\n const reader = request.body?.getReader();\n if (reader != null) {\n const decoder = new TextDecoder();\n let bytes = 0;\n try {\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n bytes += chunk.value.byteLength;\n if (bytes > MAX_REQUEST_BYTES) {\n await reader.cancel();\n return jsonResponse(413, errorBody('invalid_request_error', 'request too large'));\n }\n text += decoder.decode(chunk.value, { stream: true });\n }\n text += decoder.decode();\n } finally {\n reader.releaseLock();\n }\n }\n try {\n const value: unknown = JSON.parse(text);\n return { value };\n } catch {\n return jsonResponse(400, errorBody('invalid_request_error', 'the body is not JSON'));\n }\n};\n\nconst invalid = (error: z.ZodError): Response =>\n jsonResponse(\n 400,\n errorBody('invalid_request_error', error.issues[0]?.message ?? 'invalid request'),\n );\n\nexport const createScriptedModelHandler = (\n args: ScriptedModelHandlerArgsIface,\n): ScriptedModelHandler => {\n const timing = args.timing ?? DEFAULT_HELD_STREAM_TIMING;\n return async (request) => {\n const path = new URL(request.url).pathname.replace(/\\/+$/, '');\n if (request.method === 'GET' && path === '/healthz') return jsonResponse(200, { ok: true });\n if (args.apiKey == null) {\n return jsonResponse(\n 503,\n errorBody('api_error', 'the scripted model has no API key configured'),\n );\n }\n const presented = presentedKey(request.headers);\n if (presented == null || !(await keyMatches(presented, args.apiKey))) {\n return jsonResponse(401, errorBody('authentication_error', 'invalid API key'));\n }\n if (request.method === 'GET' && path.endsWith('/models')) {\n return jsonResponse(200, { object: 'list', data: [] });\n }\n if (request.method !== 'POST') {\n return jsonResponse(404, errorBody('not_found_error', `no route ${request.method} ${path}`));\n }\n if (path.endsWith('/messages/count_tokens')) return jsonResponse(200, { input_tokens: 12 });\n const wire = wireOfPath(path);\n if (wire == null) {\n return jsonResponse(404, errorBody('not_found_error', `no route POST ${path}`));\n }\n const body = await readJson(request);\n if (body instanceof Response) return body;\n switch (wire) {\n case ModelWire.ChatCompletions: {\n const parsed = chatCompletionsRequestSchema.safeParse(body.value);\n if (!parsed.success) return invalid(parsed.error);\n const action = scriptedAction(chatCompletionsConversation(parsed.data));\n return chatCompletionsResponse({ request: parsed.data, action, timing });\n }\n case ModelWire.Responses: {\n const parsed = responsesRequestSchema.safeParse(body.value);\n if (!parsed.success) return invalid(parsed.error);\n const action = scriptedAction(responsesConversation(parsed.data));\n return responsesResponse({ request: parsed.data, action, timing });\n }\n case ModelWire.Messages: {\n const parsed = messagesRequestSchema.safeParse(body.value);\n if (!parsed.success) return invalid(parsed.error);\n const action = scriptedAction(messagesConversation(parsed.data));\n return messagesResponse({ request: parsed.data, action, timing });\n }\n }\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["ModelWire"]
|
|
7
|
+
}
|