nexus-ai-pro 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API_STABILITY.md +225 -0
- package/CHANGELOG.md +325 -1
- package/README.md +20 -6
- package/SECURITY.md +140 -0
- package/dist/adapter-kit/contracts.d.ts +87 -0
- package/dist/adapter-kit/contracts.js +237 -0
- package/dist/adapter-kit/errors.d.ts +39 -0
- package/dist/adapter-kit/errors.js +52 -0
- package/dist/adapter-kit/index.d.ts +144 -0
- package/dist/adapter-kit/index.js +178 -0
- package/dist/adapter-kit/semver.d.ts +12 -0
- package/dist/adapter-kit/semver.js +55 -0
- package/dist/agent/capabilities.d.ts +39 -0
- package/dist/agent/capabilities.js +36 -0
- package/dist/agent/create-agent.d.ts +61 -11
- package/dist/agent/create-agent.js +136 -22
- package/dist/agent/index.d.ts +3 -2
- package/dist/agent/index.js +1 -1
- package/dist/agent/middleware/approval.d.ts +26 -0
- package/dist/agent/middleware/approval.js +23 -0
- package/dist/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
- package/dist/agent/{middleware.js → middleware/basic.js} +3 -5
- package/dist/agent/middleware/context-editor.d.ts +52 -0
- package/dist/agent/middleware/context-editor.js +66 -0
- package/dist/agent/middleware/filesystem.d.ts +44 -0
- package/dist/agent/middleware/filesystem.js +83 -0
- package/dist/agent/middleware/index.d.ts +19 -0
- package/dist/agent/middleware/index.js +9 -0
- package/dist/agent/middleware/limits.d.ts +42 -0
- package/dist/agent/middleware/limits.js +52 -0
- package/dist/agent/middleware/models.d.ts +48 -0
- package/dist/agent/middleware/models.js +44 -0
- package/dist/agent/middleware/pii.d.ts +67 -0
- package/dist/agent/middleware/pii.js +142 -0
- package/dist/agent/middleware/retry.d.ts +66 -0
- package/dist/agent/middleware/retry.js +59 -0
- package/dist/agent/middleware/shared.d.ts +41 -0
- package/dist/agent/middleware/shared.js +73 -0
- package/dist/agent/middleware/tool-selector.d.ts +64 -0
- package/dist/agent/middleware/tool-selector.js +106 -0
- package/dist/agent/permissions.d.ts +113 -0
- package/dist/agent/permissions.js +180 -0
- package/dist/agent/sandbox.d.ts +151 -0
- package/dist/agent/sandbox.js +257 -0
- package/dist/agent/tool.d.ts +8 -3
- package/dist/agent/tool.js +14 -3
- package/dist/core/secure-stream.js +4 -3
- package/dist/deep-agent/index.d.ts +109 -0
- package/dist/deep-agent/index.js +216 -0
- package/dist/embeddings/adapters.js +2 -1
- package/dist/evals/judge.js +2 -5
- package/dist/evaluate/cache.d.ts +0 -14
- package/dist/evaluate/cache.js +0 -30
- package/dist/evaluate/file-cache.d.ts +15 -0
- package/dist/evaluate/file-cache.js +30 -0
- package/dist/evaluate/index.d.ts +2 -1
- package/dist/evaluate/index.js +2 -1
- package/dist/evaluate/review.js +2 -2
- package/dist/evaluate/run.js +2 -2
- package/dist/evaluate/version.js +3 -3
- package/dist/graph/functional.d.ts +9 -0
- package/dist/graph/functional.js +20 -3
- package/dist/graph/graph.js +27 -6
- package/dist/graph/lint.d.ts +4 -1
- package/dist/graph/lint.js +35 -0
- package/dist/graph/node-cache.js +3 -3
- package/dist/hallucination/rag.d.ts +4 -1
- package/dist/hallucination/rag.js +6 -1
- package/dist/images/asset-stores.js +2 -3
- package/dist/images/asset-support.js +2 -2
- package/dist/images/assets.js +1 -2
- package/dist/images/evals.js +4 -4
- package/dist/insights/proposals.js +1 -2
- package/dist/insights/regressions.d.ts +26 -2
- package/dist/insights/regressions.js +129 -3
- package/dist/loaders/git.js +8 -1
- package/dist/loaders/web.js +7 -1
- package/dist/mcp/client.d.ts +14 -0
- package/dist/mcp/client.js +59 -1
- package/dist/mcp/registry.d.ts +6 -0
- package/dist/mcp/registry.js +7 -0
- package/dist/postgres/fulltext.d.ts +67 -0
- package/dist/postgres/fulltext.js +91 -0
- package/dist/prompts/file.js +28 -11
- package/dist/protocols/a2a.d.ts +235 -0
- package/dist/protocols/a2a.js +386 -0
- package/dist/protocols/acp.d.ts +87 -0
- package/dist/protocols/acp.js +322 -0
- package/dist/protocols/ag-ui.d.ts +120 -0
- package/dist/protocols/ag-ui.js +180 -0
- package/dist/protocols/shared.d.ts +80 -0
- package/dist/protocols/shared.js +49 -0
- package/dist/providers/anthropic.js +1 -0
- package/dist/providers/cohere.js +2 -2
- package/dist/providers/google.js +2 -11
- package/dist/providers/openai.js +1 -0
- package/dist/rag/elasticsearch.d.ts +71 -0
- package/dist/rag/elasticsearch.js +130 -0
- package/dist/rag/file-ingestion.js +15 -9
- package/dist/rag/pipeline.d.ts +140 -0
- package/dist/rag/pipeline.js +187 -0
- package/dist/rag/rerankers.d.ts +92 -0
- package/dist/rag/rerankers.js +97 -0
- package/dist/rag/retrievers.d.ts +12 -1
- package/dist/runtime/detect.d.ts +17 -0
- package/dist/runtime/detect.js +16 -0
- package/dist/runtime/index.d.ts +19 -0
- package/dist/runtime/index.js +7 -0
- package/dist/security/injection-detector.d.ts +2 -0
- package/dist/security/injection-detector.js +7 -1
- package/dist/security/input-guard.js +5 -2
- package/dist/security/output-guard.js +8 -4
- package/dist/security/pii-detector.js +22 -6
- package/dist/security/prompt-hardening.js +6 -2
- package/dist/security/semantic-injection-classifier.d.ts +2 -1
- package/dist/security/semantic-injection-classifier.js +31 -35
- package/dist/security/upload-scanner.d.ts +8 -0
- package/dist/security/upload-scanner.js +51 -9
- package/dist/server/assistant.d.ts +5 -1
- package/dist/server/assistant.js +4 -2
- package/dist/server/auth.d.ts +250 -0
- package/dist/server/auth.js +392 -0
- package/dist/server/deployments.d.ts +63 -1
- package/dist/server/deployments.js +75 -2
- package/dist/server/runs.d.ts +9 -0
- package/dist/server/runs.js +20 -0
- package/dist/server/server.js +5 -0
- package/dist/store/memory.d.ts +10 -0
- package/dist/store/memory.js +10 -0
- package/dist/testing/record.js +2 -2
- package/dist/tracing/stores.js +2 -1
- package/dist/tracing/tracer.js +2 -2
- package/dist/types/config.d.ts +20 -0
- package/dist/types/graph.d.ts +38 -0
- package/dist/types/messages.d.ts +36 -2
- package/dist/types/principal.d.ts +21 -0
- package/dist/types/principal.js +1 -0
- package/dist/types/server.d.ts +8 -9
- package/dist/utils/base64.d.ts +4 -0
- package/dist/utils/base64.js +21 -0
- package/dist/utils/checksums.d.ts +22 -0
- package/dist/utils/checksums.js +39 -0
- package/dist/utils/ids.d.ts +8 -0
- package/dist/utils/ids.js +26 -2
- package/dist/utils/sha256.d.ts +22 -0
- package/dist/utils/sha256.js +120 -0
- package/dist/utils/tenant.d.ts +11 -0
- package/dist/utils/tenant.js +14 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist-cjs/adapter-kit/contracts.d.ts +87 -0
- package/dist-cjs/adapter-kit/contracts.js +243 -0
- package/dist-cjs/adapter-kit/errors.d.ts +39 -0
- package/dist-cjs/adapter-kit/errors.js +57 -0
- package/dist-cjs/adapter-kit/index.d.ts +144 -0
- package/dist-cjs/adapter-kit/index.js +194 -0
- package/dist-cjs/adapter-kit/semver.d.ts +12 -0
- package/dist-cjs/adapter-kit/semver.js +59 -0
- package/dist-cjs/agent/capabilities.d.ts +39 -0
- package/dist-cjs/agent/capabilities.js +41 -0
- package/dist-cjs/agent/create-agent.d.ts +61 -11
- package/dist-cjs/agent/create-agent.js +136 -22
- package/dist-cjs/agent/index.d.ts +3 -2
- package/dist-cjs/agent/index.js +4 -4
- package/dist-cjs/agent/middleware/approval.d.ts +26 -0
- package/dist-cjs/agent/middleware/approval.js +26 -0
- package/dist-cjs/agent/{middleware.d.ts → middleware/basic.d.ts} +5 -4
- package/dist-cjs/agent/{middleware.js → middleware/basic.js} +3 -5
- package/dist-cjs/agent/middleware/context-editor.d.ts +52 -0
- package/dist-cjs/agent/middleware/context-editor.js +70 -0
- package/dist-cjs/agent/middleware/filesystem.d.ts +44 -0
- package/dist-cjs/agent/middleware/filesystem.js +86 -0
- package/dist-cjs/agent/middleware/index.d.ts +19 -0
- package/dist-cjs/agent/middleware/index.js +28 -0
- package/dist-cjs/agent/middleware/limits.d.ts +42 -0
- package/dist-cjs/agent/middleware/limits.js +57 -0
- package/dist-cjs/agent/middleware/models.d.ts +48 -0
- package/dist-cjs/agent/middleware/models.js +48 -0
- package/dist-cjs/agent/middleware/pii.d.ts +67 -0
- package/dist-cjs/agent/middleware/pii.js +147 -0
- package/dist-cjs/agent/middleware/retry.d.ts +66 -0
- package/dist-cjs/agent/middleware/retry.js +63 -0
- package/dist-cjs/agent/middleware/shared.d.ts +41 -0
- package/dist-cjs/agent/middleware/shared.js +83 -0
- package/dist-cjs/agent/middleware/tool-selector.d.ts +64 -0
- package/dist-cjs/agent/middleware/tool-selector.js +109 -0
- package/dist-cjs/agent/permissions.d.ts +113 -0
- package/dist-cjs/agent/permissions.js +189 -0
- package/dist-cjs/agent/sandbox.d.ts +151 -0
- package/dist-cjs/agent/sandbox.js +297 -0
- package/dist-cjs/agent/tool.d.ts +8 -3
- package/dist-cjs/agent/tool.js +14 -3
- package/dist-cjs/core/secure-stream.js +4 -3
- package/dist-cjs/deep-agent/index.d.ts +109 -0
- package/dist-cjs/deep-agent/index.js +219 -0
- package/dist-cjs/embeddings/adapters.js +2 -1
- package/dist-cjs/evals/judge.js +2 -5
- package/dist-cjs/evaluate/cache.d.ts +0 -14
- package/dist-cjs/evaluate/cache.js +1 -65
- package/dist-cjs/evaluate/file-cache.d.ts +15 -0
- package/dist-cjs/evaluate/file-cache.js +67 -0
- package/dist-cjs/evaluate/index.d.ts +2 -1
- package/dist-cjs/evaluate/index.js +3 -2
- package/dist-cjs/evaluate/review.js +2 -2
- package/dist-cjs/evaluate/run.js +2 -2
- package/dist-cjs/evaluate/version.js +3 -3
- package/dist-cjs/graph/functional.d.ts +9 -0
- package/dist-cjs/graph/functional.js +20 -3
- package/dist-cjs/graph/graph.js +27 -6
- package/dist-cjs/graph/lint.d.ts +4 -1
- package/dist-cjs/graph/lint.js +35 -0
- package/dist-cjs/graph/node-cache.js +3 -3
- package/dist-cjs/hallucination/rag.d.ts +4 -1
- package/dist-cjs/hallucination/rag.js +6 -1
- package/dist-cjs/images/asset-stores.js +2 -3
- package/dist-cjs/images/asset-support.js +2 -2
- package/dist-cjs/images/assets.js +1 -2
- package/dist-cjs/images/evals.js +4 -4
- package/dist-cjs/insights/proposals.js +1 -2
- package/dist-cjs/insights/regressions.d.ts +26 -2
- package/dist-cjs/insights/regressions.js +129 -3
- package/dist-cjs/loaders/git.js +8 -1
- package/dist-cjs/loaders/web.js +7 -1
- package/dist-cjs/mcp/client.d.ts +14 -0
- package/dist-cjs/mcp/client.js +60 -1
- package/dist-cjs/mcp/registry.d.ts +6 -0
- package/dist-cjs/mcp/registry.js +7 -0
- package/dist-cjs/postgres/fulltext.d.ts +67 -0
- package/dist-cjs/postgres/fulltext.js +129 -0
- package/dist-cjs/prompts/file.js +28 -11
- package/dist-cjs/protocols/a2a.d.ts +235 -0
- package/dist-cjs/protocols/a2a.js +393 -0
- package/dist-cjs/protocols/acp.d.ts +87 -0
- package/dist-cjs/protocols/acp.js +326 -0
- package/dist-cjs/protocols/ag-ui.d.ts +120 -0
- package/dist-cjs/protocols/ag-ui.js +186 -0
- package/dist-cjs/protocols/shared.d.ts +80 -0
- package/dist-cjs/protocols/shared.js +59 -0
- package/dist-cjs/providers/anthropic.js +1 -0
- package/dist-cjs/providers/cohere.js +2 -2
- package/dist-cjs/providers/google.js +3 -12
- package/dist-cjs/providers/openai.js +1 -0
- package/dist-cjs/rag/elasticsearch.d.ts +71 -0
- package/dist-cjs/rag/elasticsearch.js +135 -0
- package/dist-cjs/rag/file-ingestion.js +14 -8
- package/dist-cjs/rag/pipeline.d.ts +140 -0
- package/dist-cjs/rag/pipeline.js +191 -0
- package/dist-cjs/rag/rerankers.d.ts +92 -0
- package/dist-cjs/rag/rerankers.js +107 -0
- package/dist-cjs/rag/retrievers.d.ts +12 -1
- package/dist-cjs/runtime/detect.d.ts +17 -0
- package/dist-cjs/runtime/detect.js +19 -0
- package/dist-cjs/runtime/index.d.ts +19 -0
- package/dist-cjs/runtime/index.js +31 -0
- package/dist-cjs/security/injection-detector.d.ts +2 -0
- package/dist-cjs/security/injection-detector.js +7 -1
- package/dist-cjs/security/input-guard.js +5 -2
- package/dist-cjs/security/output-guard.js +8 -4
- package/dist-cjs/security/pii-detector.js +22 -6
- package/dist-cjs/security/prompt-hardening.js +6 -2
- package/dist-cjs/security/semantic-injection-classifier.d.ts +2 -1
- package/dist-cjs/security/semantic-injection-classifier.js +31 -35
- package/dist-cjs/security/upload-scanner.d.ts +8 -0
- package/dist-cjs/security/upload-scanner.js +53 -9
- package/dist-cjs/server/assistant.d.ts +5 -1
- package/dist-cjs/server/assistant.js +4 -2
- package/dist-cjs/server/auth.d.ts +250 -0
- package/dist-cjs/server/auth.js +402 -0
- package/dist-cjs/server/deployments.d.ts +63 -1
- package/dist-cjs/server/deployments.js +75 -2
- package/dist-cjs/server/runs.d.ts +9 -0
- package/dist-cjs/server/runs.js +20 -0
- package/dist-cjs/server/server.js +5 -0
- package/dist-cjs/store/memory.d.ts +10 -0
- package/dist-cjs/store/memory.js +10 -0
- package/dist-cjs/testing/record.js +2 -2
- package/dist-cjs/tracing/stores.js +2 -1
- package/dist-cjs/tracing/tracer.js +2 -2
- package/dist-cjs/types/config.d.ts +20 -0
- package/dist-cjs/types/graph.d.ts +38 -0
- package/dist-cjs/types/messages.d.ts +36 -2
- package/dist-cjs/types/principal.d.ts +21 -0
- package/dist-cjs/types/principal.js +2 -0
- package/dist-cjs/types/server.d.ts +8 -9
- package/dist-cjs/utils/base64.d.ts +4 -0
- package/dist-cjs/utils/base64.js +25 -0
- package/dist-cjs/utils/checksums.d.ts +22 -0
- package/dist-cjs/utils/checksums.js +46 -0
- package/dist-cjs/utils/ids.d.ts +8 -0
- package/dist-cjs/utils/ids.js +28 -2
- package/dist-cjs/utils/sha256.d.ts +22 -0
- package/dist-cjs/utils/sha256.js +125 -0
- package/dist-cjs/utils/tenant.d.ts +11 -0
- package/dist-cjs/utils/tenant.js +15 -0
- package/dist-cjs/version.d.ts +1 -1
- package/dist-cjs/version.js +1 -1
- package/llms.txt +7 -3
- package/package.json +193 -6
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ACP_PROTOCOL_VERSION = void 0;
|
|
4
|
+
exports.serveAcp = serveAcp;
|
|
5
|
+
const shared_js_1 = require("./shared.js");
|
|
6
|
+
exports.ACP_PROTOCOL_VERSION = 1;
|
|
7
|
+
function serveAcp(graph, streams, options = {}) {
|
|
8
|
+
const sessions = new Map();
|
|
9
|
+
const waiting = new Map();
|
|
10
|
+
let requests = 0;
|
|
11
|
+
const write = (message) => streams.output.write(`${JSON.stringify(message)}\n`);
|
|
12
|
+
const notify = (sessionId, update) => write({ jsonrpc: '2.0', method: 'session/update', params: { sessionId, update } });
|
|
13
|
+
const request = (method, params, signal) => new Promise((resolve) => {
|
|
14
|
+
const id = `agent-${++requests}`;
|
|
15
|
+
const cancel = () => {
|
|
16
|
+
waiting.delete(id);
|
|
17
|
+
resolve({ result: { outcome: { outcome: 'cancelled' } } });
|
|
18
|
+
};
|
|
19
|
+
if (signal.aborted)
|
|
20
|
+
return cancel();
|
|
21
|
+
signal.addEventListener('abort', cancel, { once: true });
|
|
22
|
+
waiting.set(id, (message) => {
|
|
23
|
+
signal.removeEventListener('abort', cancel);
|
|
24
|
+
resolve(message);
|
|
25
|
+
});
|
|
26
|
+
write({ jsonrpc: '2.0', id, method, params });
|
|
27
|
+
});
|
|
28
|
+
const kind = options.kind ?? guessKind;
|
|
29
|
+
const answerText = options.answer ?? ((prompt) => prompt);
|
|
30
|
+
const permit = async (session, interrupt, signal) => {
|
|
31
|
+
const call = (0, shared_js_1.toolCallOf)(interrupt);
|
|
32
|
+
const standing = session.always.get(call.name);
|
|
33
|
+
if (standing !== undefined)
|
|
34
|
+
return standing;
|
|
35
|
+
const response = await request('session/request_permission', {
|
|
36
|
+
sessionId: session.info.id,
|
|
37
|
+
toolCall: {
|
|
38
|
+
toolCallId: call.id,
|
|
39
|
+
title: interrupt.reason ?? titleOf(call.name, call.args),
|
|
40
|
+
kind: kind(call.name, call.args),
|
|
41
|
+
status: 'pending',
|
|
42
|
+
rawInput: call.args,
|
|
43
|
+
},
|
|
44
|
+
options: [
|
|
45
|
+
{ optionId: 'allow_once', name: 'Allow', kind: 'allow_once' },
|
|
46
|
+
{ optionId: 'allow_always', name: `Always allow ${call.name}`, kind: 'allow_always' },
|
|
47
|
+
{ optionId: 'reject_once', name: 'Reject', kind: 'reject_once' },
|
|
48
|
+
{ optionId: 'reject_always', name: `Always reject ${call.name}`, kind: 'reject_always' },
|
|
49
|
+
],
|
|
50
|
+
}, signal);
|
|
51
|
+
const outcome = response.result?.outcome;
|
|
52
|
+
if (outcome?.outcome !== 'selected')
|
|
53
|
+
return 'cancelled';
|
|
54
|
+
const allowed = outcome.optionId?.startsWith('allow') ?? false;
|
|
55
|
+
if (outcome.optionId?.endsWith('always'))
|
|
56
|
+
session.always.set(call.name, allowed);
|
|
57
|
+
return allowed;
|
|
58
|
+
};
|
|
59
|
+
const prompt = async (session, blocks) => {
|
|
60
|
+
session.controller?.abort();
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
session.controller = controller;
|
|
63
|
+
const id = session.info.id;
|
|
64
|
+
const text = promptText(blocks);
|
|
65
|
+
let spoke = false;
|
|
66
|
+
const calls = new Map();
|
|
67
|
+
const runOptions = {
|
|
68
|
+
threadId: id,
|
|
69
|
+
signal: controller.signal,
|
|
70
|
+
...(options.principal ? { principal: options.principal } : {}),
|
|
71
|
+
onEvent: (event) => {
|
|
72
|
+
if (event.namespace)
|
|
73
|
+
return;
|
|
74
|
+
if (event.type === 'message' && event.chunk.content) {
|
|
75
|
+
spoke = true;
|
|
76
|
+
notify(id, {
|
|
77
|
+
sessionUpdate: event.chunk.kind === 'reasoning' ? 'agent_thought_chunk' : 'agent_message_chunk',
|
|
78
|
+
content: { type: 'text', text: event.chunk.content },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (event.type === 'tool') {
|
|
82
|
+
spoke = false;
|
|
83
|
+
for (const update of toolUpdates(event.tool, kind, calls))
|
|
84
|
+
notify(id, update);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
try {
|
|
89
|
+
return await turn(session, text, runOptions, controller.signal, () => spoke);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (controller.signal.aborted)
|
|
93
|
+
return 'cancelled';
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const turn = async (session, text, runOptions, signal, spoke) => {
|
|
98
|
+
const id = session.info.id;
|
|
99
|
+
const user = (0, shared_js_1.messageOf)('user', text);
|
|
100
|
+
let result;
|
|
101
|
+
if (session.pending?.length) {
|
|
102
|
+
const answers = {
|
|
103
|
+
...session.answered,
|
|
104
|
+
...Object.fromEntries(session.pending.map((item) => [item.id, answerText(text, item)])),
|
|
105
|
+
};
|
|
106
|
+
session.pending = undefined;
|
|
107
|
+
session.answered = undefined;
|
|
108
|
+
session.history.push(user);
|
|
109
|
+
result = await graph.resumeInterruptsWith(id, answers, runOptions);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const history = session.history;
|
|
113
|
+
result = await graph.invoke(options.input ? options.input(text, session.info, history) : { messages: [...history, user] }, runOptions);
|
|
114
|
+
session.history = [...history, user];
|
|
115
|
+
}
|
|
116
|
+
while (result.status === 'awaiting_input' && result.interrupts?.length) {
|
|
117
|
+
if (signal.aborted)
|
|
118
|
+
return 'cancelled';
|
|
119
|
+
const approvals = result.interrupts.filter((item) => (0, shared_js_1.toolCallOf)(item));
|
|
120
|
+
const questions = result.interrupts.filter((item) => !(0, shared_js_1.toolCallOf)(item));
|
|
121
|
+
const answers = {};
|
|
122
|
+
for (const interrupt of approvals) {
|
|
123
|
+
const decision = await permit(session, interrupt, signal);
|
|
124
|
+
if (decision === 'cancelled')
|
|
125
|
+
return 'cancelled';
|
|
126
|
+
answers[interrupt.id] = decision;
|
|
127
|
+
}
|
|
128
|
+
if (questions.length) {
|
|
129
|
+
notify(id, {
|
|
130
|
+
sessionUpdate: 'agent_message_chunk',
|
|
131
|
+
content: { type: 'text', text: questions.map(questionOf).join('\n') },
|
|
132
|
+
});
|
|
133
|
+
session.pending = questions;
|
|
134
|
+
session.answered = answers;
|
|
135
|
+
return 'end_turn';
|
|
136
|
+
}
|
|
137
|
+
result = await graph.resumeInterruptsWith(id, answers, runOptions);
|
|
138
|
+
}
|
|
139
|
+
if (signal.aborted || result.status === 'interrupted')
|
|
140
|
+
return 'cancelled';
|
|
141
|
+
const answer = (0, shared_js_1.answerOf)(result.state);
|
|
142
|
+
if (!spoke() && answer)
|
|
143
|
+
notify(id, { sessionUpdate: 'agent_message_chunk', content: { type: 'text', text: answer } });
|
|
144
|
+
session.history = (0, shared_js_1.transcriptOf)(result.state, [...session.history, (0, shared_js_1.messageOf)('assistant', answer)]);
|
|
145
|
+
return result.state?.stopReason === 'max_iterations'
|
|
146
|
+
? 'max_turn_requests'
|
|
147
|
+
: 'end_turn';
|
|
148
|
+
};
|
|
149
|
+
const handle = async (message) => {
|
|
150
|
+
const params = message.params ?? {};
|
|
151
|
+
switch (message.method) {
|
|
152
|
+
case 'initialize':
|
|
153
|
+
return {
|
|
154
|
+
protocolVersion: exports.ACP_PROTOCOL_VERSION,
|
|
155
|
+
agentCapabilities: {
|
|
156
|
+
loadSession: false,
|
|
157
|
+
promptCapabilities: { image: false, audio: false, embeddedContext: true },
|
|
158
|
+
},
|
|
159
|
+
authMethods: [],
|
|
160
|
+
...(options.agentInfo ? { agentInfo: options.agentInfo } : {}),
|
|
161
|
+
};
|
|
162
|
+
case 'authenticate':
|
|
163
|
+
return {};
|
|
164
|
+
case 'session/new': {
|
|
165
|
+
const info = {
|
|
166
|
+
id: (0, shared_js_1.protocolId)('session'),
|
|
167
|
+
cwd: typeof params.cwd === 'string' ? params.cwd : '',
|
|
168
|
+
mcpServers: Array.isArray(params.mcpServers) ? params.mcpServers : [],
|
|
169
|
+
};
|
|
170
|
+
sessions.set(info.id, { info, history: [], always: new Map() });
|
|
171
|
+
return { sessionId: info.id };
|
|
172
|
+
}
|
|
173
|
+
case 'session/prompt': {
|
|
174
|
+
const session = sessions.get(String(params.sessionId));
|
|
175
|
+
if (!session)
|
|
176
|
+
throw Object.assign(new Error(`Session ${String(params.sessionId)} was not found`), { code: -32602 });
|
|
177
|
+
return {
|
|
178
|
+
stopReason: await prompt(session, Array.isArray(params.prompt) ? params.prompt : []),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
default:
|
|
182
|
+
throw Object.assign(new Error(`Method ${String(message.method)} is not supported`), { code: -32601 });
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const receive = (message) => {
|
|
186
|
+
if (message.method === undefined) {
|
|
187
|
+
if (message.id !== undefined && message.id !== null)
|
|
188
|
+
waiting.get(message.id)?.(message);
|
|
189
|
+
waiting.delete(message.id);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (message.id === undefined || message.id === null) {
|
|
193
|
+
if (message.method === 'session/cancel')
|
|
194
|
+
sessions.get(String(message.params?.sessionId))?.controller?.abort();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
handle(message).then((result) => write({ jsonrpc: '2.0', id: message.id, result }), (error) => write({
|
|
198
|
+
jsonrpc: '2.0',
|
|
199
|
+
id: message.id,
|
|
200
|
+
error: { code: typeof error.code === 'number' ? error.code : -32603, message: error.message },
|
|
201
|
+
}));
|
|
202
|
+
};
|
|
203
|
+
const closed = (async () => {
|
|
204
|
+
const decoder = new TextDecoder();
|
|
205
|
+
let buffer = '';
|
|
206
|
+
for await (const chunk of streams.input) {
|
|
207
|
+
buffer += typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });
|
|
208
|
+
let newline = buffer.indexOf('\n');
|
|
209
|
+
while (newline !== -1) {
|
|
210
|
+
const line = buffer.slice(0, newline).trim();
|
|
211
|
+
buffer = buffer.slice(newline + 1);
|
|
212
|
+
if (line) {
|
|
213
|
+
try {
|
|
214
|
+
receive(JSON.parse(line));
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
write({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'A line is not JSON' } });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
newline = buffer.indexOf('\n');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
})();
|
|
224
|
+
return {
|
|
225
|
+
closed,
|
|
226
|
+
close() {
|
|
227
|
+
for (const session of sessions.values())
|
|
228
|
+
session.controller?.abort();
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
function toolUpdates(tool, kind, calls) {
|
|
233
|
+
const args = (tool.args ?? calls.get(tool.id) ?? {});
|
|
234
|
+
if (tool.phase === 'start') {
|
|
235
|
+
calls.set(tool.id, args);
|
|
236
|
+
const updates = [
|
|
237
|
+
{
|
|
238
|
+
sessionUpdate: 'tool_call',
|
|
239
|
+
toolCallId: tool.id,
|
|
240
|
+
title: titleOf(tool.name, args),
|
|
241
|
+
kind: kind(tool.name, args),
|
|
242
|
+
status: 'in_progress',
|
|
243
|
+
rawInput: args,
|
|
244
|
+
...(typeof args.path === 'string' ? { locations: [{ path: args.path }] } : {}),
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
if (tool.name === 'write_todos' && Array.isArray(args.todos)) {
|
|
248
|
+
updates.push({
|
|
249
|
+
sessionUpdate: 'plan',
|
|
250
|
+
entries: args.todos.map((todo) => ({
|
|
251
|
+
content: String(todo.content ?? ''),
|
|
252
|
+
priority: 'medium',
|
|
253
|
+
status: todo.status === 'in_progress' || todo.status === 'completed' ? todo.status : 'pending',
|
|
254
|
+
})),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return updates;
|
|
258
|
+
}
|
|
259
|
+
if (tool.phase !== 'result' && tool.phase !== 'error')
|
|
260
|
+
return [];
|
|
261
|
+
const content = [];
|
|
262
|
+
if (tool.phase === 'result' && typeof args.path === 'string') {
|
|
263
|
+
const oldText = args.old_text ?? args.oldText;
|
|
264
|
+
const newText = args.new_text ?? args.newText ?? (tool.name === 'write_file' ? args.content : undefined);
|
|
265
|
+
if (typeof newText === 'string') {
|
|
266
|
+
content.push({ type: 'diff', path: args.path, oldText: typeof oldText === 'string' ? oldText : null, newText });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
content.push({
|
|
270
|
+
type: 'content',
|
|
271
|
+
content: { type: 'text', text: tool.phase === 'result' ? (0, shared_js_1.asText)(tool.result) : (tool.error ?? 'The tool failed') },
|
|
272
|
+
});
|
|
273
|
+
return [
|
|
274
|
+
{
|
|
275
|
+
sessionUpdate: 'tool_call_update',
|
|
276
|
+
toolCallId: tool.id,
|
|
277
|
+
status: tool.phase === 'result' ? 'completed' : 'failed',
|
|
278
|
+
content,
|
|
279
|
+
...(tool.phase === 'result' ? { rawOutput: tool.result } : {}),
|
|
280
|
+
},
|
|
281
|
+
];
|
|
282
|
+
}
|
|
283
|
+
function guessKind(name) {
|
|
284
|
+
const lower = name.toLowerCase();
|
|
285
|
+
if (lower === 'write_todos' || /think|plan/.test(lower))
|
|
286
|
+
return 'think';
|
|
287
|
+
if (/delete|remove|^rm$/.test(lower))
|
|
288
|
+
return 'delete';
|
|
289
|
+
if (/move|rename|^mv$/.test(lower))
|
|
290
|
+
return 'move';
|
|
291
|
+
if (/edit|write|patch|replace|create/.test(lower))
|
|
292
|
+
return 'edit';
|
|
293
|
+
if (/grep|glob|search|find|query/.test(lower))
|
|
294
|
+
return 'search';
|
|
295
|
+
if (/read|^ls$|list|cat|open|view/.test(lower))
|
|
296
|
+
return 'read';
|
|
297
|
+
if (/exec|shell|bash|run|command|terminal/.test(lower))
|
|
298
|
+
return 'execute';
|
|
299
|
+
if (/fetch|http|url|web|download|browse/.test(lower))
|
|
300
|
+
return 'fetch';
|
|
301
|
+
return 'other';
|
|
302
|
+
}
|
|
303
|
+
function titleOf(name, args) {
|
|
304
|
+
const values = (args ?? {});
|
|
305
|
+
const subject = [values.path, values.command, values.query, values.url, values.pattern].find((value) => typeof value === 'string');
|
|
306
|
+
return subject ? `${name} ${subject}` : name;
|
|
307
|
+
}
|
|
308
|
+
function questionOf(interrupt) {
|
|
309
|
+
return (interrupt.reason ??
|
|
310
|
+
(interrupt.payload === undefined ? 'The agent needs an answer to continue.' : (0, shared_js_1.asText)(interrupt.payload)));
|
|
311
|
+
}
|
|
312
|
+
function promptText(blocks) {
|
|
313
|
+
return blocks
|
|
314
|
+
.map((block) => {
|
|
315
|
+
if (block.type === 'text')
|
|
316
|
+
return block.text ?? '';
|
|
317
|
+
if (block.type === 'resource' && typeof block.resource?.text === 'string') {
|
|
318
|
+
return `${block.resource.uri}\n\`\`\`\n${block.resource.text}\n\`\`\``;
|
|
319
|
+
}
|
|
320
|
+
if (block.type === 'resource_link' && block.uri)
|
|
321
|
+
return `@${block.uri}`;
|
|
322
|
+
return '';
|
|
323
|
+
})
|
|
324
|
+
.filter(Boolean)
|
|
325
|
+
.join('\n\n');
|
|
326
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Message } from '../types/messages.js';
|
|
2
|
+
import type { Principal } from '../types/principal.js';
|
|
3
|
+
import { type ProtocolGraph } from './shared.js';
|
|
4
|
+
export type { ProtocolGraph, ProtocolInterrupt, ProtocolResult, ProtocolRunOptions } from './shared.js';
|
|
5
|
+
/** A message in AG-UI's shape. */
|
|
6
|
+
export interface AgUiMessage {
|
|
7
|
+
/** Its id. */
|
|
8
|
+
id: string;
|
|
9
|
+
/** `user`, `assistant`, `system`, `developer`, or `tool`; other roles are passed over. */
|
|
10
|
+
role: string;
|
|
11
|
+
/** Its text, or a list of parts with text. */
|
|
12
|
+
content?: unknown;
|
|
13
|
+
/** The tool calls an assistant message made. */
|
|
14
|
+
toolCalls?: Array<{
|
|
15
|
+
id: string;
|
|
16
|
+
type: 'function';
|
|
17
|
+
function: {
|
|
18
|
+
name: string;
|
|
19
|
+
arguments: string;
|
|
20
|
+
};
|
|
21
|
+
}>;
|
|
22
|
+
/** The call a tool message answers. */
|
|
23
|
+
toolCallId?: string;
|
|
24
|
+
}
|
|
25
|
+
/** One answer to an interrupt, in a resumed run. */
|
|
26
|
+
export interface AgUiResumeEntry {
|
|
27
|
+
/** The interrupt it answers. */
|
|
28
|
+
interruptId: string;
|
|
29
|
+
/** `resolved` with a payload, or `cancelled`. */
|
|
30
|
+
status: 'resolved' | 'cancelled';
|
|
31
|
+
/** The answer. */
|
|
32
|
+
payload?: unknown;
|
|
33
|
+
}
|
|
34
|
+
/** What a frontend sends to start or resume a run: AG-UI's `RunAgentInput`. */
|
|
35
|
+
export interface AgUiRunInput {
|
|
36
|
+
/** The conversation. */
|
|
37
|
+
threadId: string;
|
|
38
|
+
/** This run. */
|
|
39
|
+
runId: string;
|
|
40
|
+
/** The run this one continues, when it does. */
|
|
41
|
+
parentRunId?: string;
|
|
42
|
+
/** The whole conversation so far. */
|
|
43
|
+
messages: AgUiMessage[];
|
|
44
|
+
/** Tools the frontend offers. Passed to `input` for an application that uses them. */
|
|
45
|
+
tools?: Array<{
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
parameters: unknown;
|
|
49
|
+
}>;
|
|
50
|
+
/** Extra context the frontend supplies. */
|
|
51
|
+
context?: Array<{
|
|
52
|
+
description: string;
|
|
53
|
+
value: string;
|
|
54
|
+
}>;
|
|
55
|
+
/** Shared state, when the frontend keeps any. */
|
|
56
|
+
state?: unknown;
|
|
57
|
+
/** Anything else the frontend forwards. */
|
|
58
|
+
forwardedProps?: unknown;
|
|
59
|
+
/** Answers to the questions a paused run asked. */
|
|
60
|
+
resume?: AgUiResumeEntry[];
|
|
61
|
+
}
|
|
62
|
+
/** A question a paused run asks, in AG-UI's shape. */
|
|
63
|
+
export interface AgUiInterrupt {
|
|
64
|
+
/** Its id, which a resume entry names. */
|
|
65
|
+
id: string;
|
|
66
|
+
/** `tool_call` for an approval, `input_required` for anything else. */
|
|
67
|
+
reason: string;
|
|
68
|
+
/** The question, for a person. */
|
|
69
|
+
message?: string;
|
|
70
|
+
/** The tool call awaiting approval, when it is one. */
|
|
71
|
+
toolCallId?: string;
|
|
72
|
+
/** What the run asked about, whole. */
|
|
73
|
+
metadata?: Record<string, unknown>;
|
|
74
|
+
}
|
|
75
|
+
/** An AG-UI event, as the stream carries it. */
|
|
76
|
+
export type AgUiEvent = {
|
|
77
|
+
type: string;
|
|
78
|
+
timestamp?: number;
|
|
79
|
+
} & Record<string, unknown>;
|
|
80
|
+
/** Options for `agUiEvents()` and `agUiHandler()`. */
|
|
81
|
+
export interface AgUiOptions {
|
|
82
|
+
/**
|
|
83
|
+
* The graph input for a run. Defaults to `{ messages }`, the conversation as Nexus messages,
|
|
84
|
+
* which is what an agent from `createAgent()` takes.
|
|
85
|
+
*/
|
|
86
|
+
input?: (run: AgUiRunInput, messages: Message[]) => unknown;
|
|
87
|
+
/** The answer a resume entry gives a question. Defaults to its payload, `true` when it has none, and `false` when cancelled. */
|
|
88
|
+
answer?: (entry: AgUiResumeEntry) => unknown;
|
|
89
|
+
/** Who the run is for, from the request: the place to authenticate a frontend's caller. */
|
|
90
|
+
principal?: (request: Request) => Principal | undefined | Promise<Principal | undefined>;
|
|
91
|
+
/** Adds a `STATE_SNAPSHOT` with the final state before the run finishes. Defaults to true. */
|
|
92
|
+
stateSnapshot?: boolean;
|
|
93
|
+
}
|
|
94
|
+
/** Options for `agUiEvents()`: everything `agUiHandler()` takes, with the caller already known. */
|
|
95
|
+
export interface AgUiEventsOptions extends Omit<AgUiOptions, 'principal'> {
|
|
96
|
+
/** Stops the run. */
|
|
97
|
+
signal?: AbortSignal;
|
|
98
|
+
/** Who the run is for. */
|
|
99
|
+
principal?: Principal;
|
|
100
|
+
}
|
|
101
|
+
/** The conversation from a `RunAgentInput`, as Nexus messages. */
|
|
102
|
+
export declare function agUiMessages(messages: readonly AgUiMessage[]): Message[];
|
|
103
|
+
/**
|
|
104
|
+
* A run as AG-UI events, for any transport: Server-Sent Events, a WebSocket, a test. Events are
|
|
105
|
+
* produced as the graph emits them; the last is `RUN_FINISHED` or `RUN_ERROR`.
|
|
106
|
+
*/
|
|
107
|
+
export declare function agUiEvents(graph: ProtocolGraph, run: AgUiRunInput, options?: AgUiEventsOptions): AsyncGenerator<AgUiEvent>;
|
|
108
|
+
/**
|
|
109
|
+
* An HTTP handler that serves a graph to AG-UI frontends: POST a `RunAgentInput`, read the run as
|
|
110
|
+
* Server-Sent Events. Mount it on any route, under any framework that speaks `Request` and
|
|
111
|
+
* `Response`.
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* const handler = agUiHandler(agent);
|
|
115
|
+
* app.post('/agent', (request) => handler(request));
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare function agUiHandler(graph: ProtocolGraph, options?: AgUiOptions): (request: Request) => Promise<Response>;
|
|
119
|
+
/** One event as a Server-Sent Event: `data: <json>` and a blank line. */
|
|
120
|
+
export declare function encodeAgUiEvent(event: AgUiEvent): string;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agUiMessages = agUiMessages;
|
|
4
|
+
exports.agUiEvents = agUiEvents;
|
|
5
|
+
exports.agUiHandler = agUiHandler;
|
|
6
|
+
exports.encodeAgUiEvent = encodeAgUiEvent;
|
|
7
|
+
const shared_js_1 = require("./shared.js");
|
|
8
|
+
function agUiMessages(messages) {
|
|
9
|
+
const converted = [];
|
|
10
|
+
for (const message of messages) {
|
|
11
|
+
if (!['user', 'assistant', 'system', 'developer', 'tool'].includes(message.role))
|
|
12
|
+
continue;
|
|
13
|
+
const content = (0, shared_js_1.textOf)(message.content);
|
|
14
|
+
converted.push((0, shared_js_1.messageOf)(message.role, content, {
|
|
15
|
+
...(message.toolCalls?.length ? { toolCalls: message.toolCalls } : {}),
|
|
16
|
+
...(message.role === 'tool' && message.toolCallId ? { toolCallId: message.toolCallId } : {}),
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
return converted;
|
|
20
|
+
}
|
|
21
|
+
async function* agUiEvents(graph, run, options = {}) {
|
|
22
|
+
const queue = [];
|
|
23
|
+
let wake;
|
|
24
|
+
let done = false;
|
|
25
|
+
const push = (event) => {
|
|
26
|
+
queue.push({ ...event, timestamp: Date.now() });
|
|
27
|
+
wake?.();
|
|
28
|
+
};
|
|
29
|
+
const translate = translator(push);
|
|
30
|
+
push({
|
|
31
|
+
type: 'RUN_STARTED',
|
|
32
|
+
threadId: run.threadId,
|
|
33
|
+
runId: run.runId,
|
|
34
|
+
...(run.parentRunId ? { parentRunId: run.parentRunId } : {}),
|
|
35
|
+
});
|
|
36
|
+
const runOptions = {
|
|
37
|
+
threadId: run.threadId,
|
|
38
|
+
onEvent: translate.event,
|
|
39
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
40
|
+
...(options.principal ? { principal: options.principal } : {}),
|
|
41
|
+
};
|
|
42
|
+
const finished = (async () => {
|
|
43
|
+
try {
|
|
44
|
+
let result;
|
|
45
|
+
if (run.resume?.length) {
|
|
46
|
+
const answer = options.answer ??
|
|
47
|
+
((entry) => (entry.status === 'cancelled' ? false : (entry.payload ?? true)));
|
|
48
|
+
result = await graph.resumeInterruptsWith(run.threadId, Object.fromEntries(run.resume.map((entry) => [entry.interruptId, answer(entry)])), runOptions);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const messages = agUiMessages(run.messages);
|
|
52
|
+
result = await graph.invoke(options.input ? options.input(run, messages) : { messages }, runOptions);
|
|
53
|
+
}
|
|
54
|
+
translate.close();
|
|
55
|
+
if (options.stateSnapshot !== false)
|
|
56
|
+
push({ type: 'STATE_SNAPSHOT', snapshot: result.state });
|
|
57
|
+
push(finishedEvent(run, result));
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
translate.close();
|
|
61
|
+
push({
|
|
62
|
+
type: 'RUN_ERROR',
|
|
63
|
+
message: error instanceof Error ? error.message : String(error),
|
|
64
|
+
...(error?.code ? { code: String(error.code) } : {}),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
done = true;
|
|
69
|
+
wake?.();
|
|
70
|
+
}
|
|
71
|
+
})();
|
|
72
|
+
while (true) {
|
|
73
|
+
if (queue.length > 0) {
|
|
74
|
+
yield queue.shift();
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (done)
|
|
78
|
+
break;
|
|
79
|
+
await new Promise((resolve) => {
|
|
80
|
+
wake = resolve;
|
|
81
|
+
});
|
|
82
|
+
wake = undefined;
|
|
83
|
+
}
|
|
84
|
+
await finished;
|
|
85
|
+
}
|
|
86
|
+
function agUiHandler(graph, options = {}) {
|
|
87
|
+
return async (request) => {
|
|
88
|
+
if (request.method !== 'POST')
|
|
89
|
+
return new Response('AG-UI runs are POSTed', { status: 405, headers: { allow: 'POST' } });
|
|
90
|
+
let run;
|
|
91
|
+
try {
|
|
92
|
+
run = (await request.json());
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return new Response('The body is not a RunAgentInput', { status: 400 });
|
|
96
|
+
}
|
|
97
|
+
if (typeof run?.threadId !== 'string' || (!Array.isArray(run.messages) && !run.resume)) {
|
|
98
|
+
return new Response('A RunAgentInput needs a threadId and messages', { status: 400 });
|
|
99
|
+
}
|
|
100
|
+
run = { ...run, runId: run.runId || (0, shared_js_1.protocolId)('run'), messages: run.messages ?? [] };
|
|
101
|
+
const caller = await options.principal?.(request);
|
|
102
|
+
const encoder = new TextEncoder();
|
|
103
|
+
const body = new ReadableStream({
|
|
104
|
+
async start(controller) {
|
|
105
|
+
const { principal: _resolve, ...rest } = options;
|
|
106
|
+
for await (const event of agUiEvents(graph, run, {
|
|
107
|
+
...rest,
|
|
108
|
+
signal: request.signal,
|
|
109
|
+
...(caller ? { principal: caller } : {}),
|
|
110
|
+
})) {
|
|
111
|
+
controller.enqueue(encoder.encode(encodeAgUiEvent(event)));
|
|
112
|
+
}
|
|
113
|
+
controller.close();
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
return new Response(body, {
|
|
117
|
+
headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache', connection: 'keep-alive' },
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function encodeAgUiEvent(event) {
|
|
122
|
+
return `data: ${JSON.stringify(event)}\n\n`;
|
|
123
|
+
}
|
|
124
|
+
function translator(push) {
|
|
125
|
+
let open;
|
|
126
|
+
const closeMessage = () => {
|
|
127
|
+
if (open)
|
|
128
|
+
push({ type: 'TEXT_MESSAGE_END', messageId: open });
|
|
129
|
+
open = undefined;
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
event(event) {
|
|
133
|
+
if (event.type === 'task_start' && !event.namespace)
|
|
134
|
+
push({ type: 'STEP_STARTED', stepName: event.node });
|
|
135
|
+
else if (event.type === 'task_end' && !event.namespace) {
|
|
136
|
+
closeMessage();
|
|
137
|
+
push({ type: 'STEP_FINISHED', stepName: event.node });
|
|
138
|
+
}
|
|
139
|
+
else if (event.type === 'message' && event.chunk.kind !== 'reasoning' && event.chunk.content) {
|
|
140
|
+
const messageId = event.chunk.messageId ?? `${event.taskId}:${event.step}`;
|
|
141
|
+
if (open !== messageId) {
|
|
142
|
+
closeMessage();
|
|
143
|
+
open = messageId;
|
|
144
|
+
push({ type: 'TEXT_MESSAGE_START', messageId, role: 'assistant' });
|
|
145
|
+
}
|
|
146
|
+
push({ type: 'TEXT_MESSAGE_CONTENT', messageId, delta: event.chunk.content });
|
|
147
|
+
}
|
|
148
|
+
else if (event.type === 'tool') {
|
|
149
|
+
closeMessage();
|
|
150
|
+
const tool = event.tool;
|
|
151
|
+
if (tool.phase === 'start') {
|
|
152
|
+
push({ type: 'TOOL_CALL_START', toolCallId: tool.id, toolCallName: tool.name });
|
|
153
|
+
push({ type: 'TOOL_CALL_ARGS', toolCallId: tool.id, delta: (0, shared_js_1.asText)(tool.args ?? {}) });
|
|
154
|
+
push({ type: 'TOOL_CALL_END', toolCallId: tool.id });
|
|
155
|
+
}
|
|
156
|
+
else if (tool.phase === 'result' || tool.phase === 'error') {
|
|
157
|
+
push({
|
|
158
|
+
type: 'TOOL_CALL_RESULT',
|
|
159
|
+
messageId: `${tool.id}:result`,
|
|
160
|
+
toolCallId: tool.id,
|
|
161
|
+
role: 'tool',
|
|
162
|
+
content: tool.phase === 'result' ? (0, shared_js_1.asText)(tool.result) : (tool.error ?? 'The tool failed'),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
close: closeMessage,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function finishedEvent(run, result) {
|
|
171
|
+
const base = { type: 'RUN_FINISHED', threadId: run.threadId, runId: run.runId };
|
|
172
|
+
if (result.status === 'awaiting_input' && result.interrupts?.length) {
|
|
173
|
+
return { ...base, outcome: { type: 'interrupt', interrupts: result.interrupts.map(agUiInterrupt) } };
|
|
174
|
+
}
|
|
175
|
+
return { ...base, outcome: { type: 'success' }, result: (0, shared_js_1.answerOf)(result.state) };
|
|
176
|
+
}
|
|
177
|
+
function agUiInterrupt(interrupt) {
|
|
178
|
+
const call = (0, shared_js_1.toolCallOf)(interrupt);
|
|
179
|
+
return {
|
|
180
|
+
id: interrupt.id,
|
|
181
|
+
reason: call ? 'tool_call' : 'input_required',
|
|
182
|
+
...(interrupt.reason ? { message: interrupt.reason } : {}),
|
|
183
|
+
...(call ? { toolCallId: call.id } : {}),
|
|
184
|
+
...(interrupt.payload === undefined ? {} : { metadata: { payload: interrupt.payload } }),
|
|
185
|
+
};
|
|
186
|
+
}
|