@copilotkit/aimock 1.7.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/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +12 -0
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/dist/_virtual/_rolldown/runtime.cjs +29 -0
- package/dist/a2a-handler.cjs +203 -0
- package/dist/a2a-handler.cjs.map +1 -0
- package/dist/a2a-handler.js +199 -0
- package/dist/a2a-handler.js.map +1 -0
- package/dist/a2a-mock.cjs +292 -0
- package/dist/a2a-mock.cjs.map +1 -0
- package/dist/a2a-mock.d.cts +41 -0
- package/dist/a2a-mock.d.cts.map +1 -0
- package/dist/a2a-mock.d.ts +41 -0
- package/dist/a2a-mock.d.ts.map +1 -0
- package/dist/a2a-mock.js +290 -0
- package/dist/a2a-mock.js.map +1 -0
- package/dist/a2a-stub.cjs +4 -0
- package/dist/a2a-stub.d.cts +3 -0
- package/dist/a2a-stub.d.ts +3 -0
- package/dist/a2a-stub.js +3 -0
- package/dist/a2a-types.d.cts +68 -0
- package/dist/a2a-types.d.cts.map +1 -0
- package/dist/a2a-types.d.ts +68 -0
- package/dist/a2a-types.d.ts.map +1 -0
- package/dist/aimock-cli.cjs +112 -0
- package/dist/aimock-cli.cjs.map +1 -0
- package/dist/aimock-cli.d.cts +19 -0
- package/dist/aimock-cli.d.cts.map +1 -0
- package/dist/aimock-cli.d.ts +19 -0
- package/dist/aimock-cli.d.ts.map +1 -0
- package/dist/aimock-cli.js +110 -0
- package/dist/aimock-cli.js.map +1 -0
- package/dist/aws-event-stream.cjs +117 -0
- package/dist/aws-event-stream.cjs.map +1 -0
- package/dist/aws-event-stream.d.cts +38 -0
- package/dist/aws-event-stream.d.cts.map +1 -0
- package/dist/aws-event-stream.d.ts +38 -0
- package/dist/aws-event-stream.d.ts.map +1 -0
- package/dist/aws-event-stream.js +114 -0
- package/dist/aws-event-stream.js.map +1 -0
- package/dist/bedrock-converse.cjs +445 -0
- package/dist/bedrock-converse.cjs.map +1 -0
- package/dist/bedrock-converse.d.cts +50 -0
- package/dist/bedrock-converse.d.cts.map +1 -0
- package/dist/bedrock-converse.d.ts +50 -0
- package/dist/bedrock-converse.d.ts.map +1 -0
- package/dist/bedrock-converse.js +443 -0
- package/dist/bedrock-converse.js.map +1 -0
- package/dist/bedrock.cjs +557 -0
- package/dist/bedrock.cjs.map +1 -0
- package/dist/bedrock.d.cts +41 -0
- package/dist/bedrock.d.cts.map +1 -0
- package/dist/bedrock.d.ts +41 -0
- package/dist/bedrock.d.ts.map +1 -0
- package/dist/bedrock.js +553 -0
- package/dist/bedrock.js.map +1 -0
- package/dist/chaos.cjs +114 -0
- package/dist/chaos.cjs.map +1 -0
- package/dist/chaos.d.cts +27 -0
- package/dist/chaos.d.cts.map +1 -0
- package/dist/chaos.d.ts +27 -0
- package/dist/chaos.d.ts.map +1 -0
- package/dist/chaos.js +113 -0
- package/dist/chaos.js.map +1 -0
- package/dist/cli.cjs +268 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +268 -0
- package/dist/cli.js.map +1 -0
- package/dist/cohere.cjs +434 -0
- package/dist/cohere.cjs.map +1 -0
- package/dist/cohere.d.cts +34 -0
- package/dist/cohere.d.cts.map +1 -0
- package/dist/cohere.d.ts +34 -0
- package/dist/cohere.d.ts.map +1 -0
- package/dist/cohere.js +433 -0
- package/dist/cohere.js.map +1 -0
- package/dist/config-loader.cjs +111 -0
- package/dist/config-loader.cjs.map +1 -0
- package/dist/config-loader.d.cts +100 -0
- package/dist/config-loader.d.cts.map +1 -0
- package/dist/config-loader.d.ts +100 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +107 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/embeddings.cjs +150 -0
- package/dist/embeddings.cjs.map +1 -0
- package/dist/embeddings.d.cts +12 -0
- package/dist/embeddings.d.cts.map +1 -0
- package/dist/embeddings.d.ts +12 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +150 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/fixture-loader.cjs +269 -0
- package/dist/fixture-loader.cjs.map +1 -0
- package/dist/fixture-loader.d.cts +17 -0
- package/dist/fixture-loader.d.cts.map +1 -0
- package/dist/fixture-loader.d.ts +17 -0
- package/dist/fixture-loader.d.ts.map +1 -0
- package/dist/fixture-loader.js +265 -0
- package/dist/fixture-loader.js.map +1 -0
- package/dist/gemini.cjs +403 -0
- package/dist/gemini.cjs.map +1 -0
- package/dist/gemini.d.cts +10 -0
- package/dist/gemini.d.cts.map +1 -0
- package/dist/gemini.d.ts +10 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +403 -0
- package/dist/gemini.js.map +1 -0
- package/dist/helpers.cjs +276 -0
- package/dist/helpers.cjs.map +1 -0
- package/dist/helpers.d.cts +39 -0
- package/dist/helpers.d.cts.map +1 -0
- package/dist/helpers.d.ts +39 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +259 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.cjs +113 -0
- package/dist/index.d.cts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +39 -0
- package/dist/interruption.cjs +40 -0
- package/dist/interruption.cjs.map +1 -0
- package/dist/interruption.d.cts +15 -0
- package/dist/interruption.d.cts.map +1 -0
- package/dist/interruption.d.ts +15 -0
- package/dist/interruption.d.ts.map +1 -0
- package/dist/interruption.js +39 -0
- package/dist/interruption.js.map +1 -0
- package/dist/journal.cjs +65 -0
- package/dist/journal.cjs.map +1 -0
- package/dist/journal.d.cts +23 -0
- package/dist/journal.d.cts.map +1 -0
- package/dist/journal.d.ts +23 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +65 -0
- package/dist/journal.js.map +1 -0
- package/dist/jsonrpc.cjs +91 -0
- package/dist/jsonrpc.cjs.map +1 -0
- package/dist/jsonrpc.d.cts +24 -0
- package/dist/jsonrpc.d.cts.map +1 -0
- package/dist/jsonrpc.d.ts +24 -0
- package/dist/jsonrpc.d.ts.map +1 -0
- package/dist/jsonrpc.js +90 -0
- package/dist/jsonrpc.js.map +1 -0
- package/dist/llmock.cjs +223 -0
- package/dist/llmock.cjs.map +1 -0
- package/dist/llmock.d.cts +70 -0
- package/dist/llmock.d.cts.map +1 -0
- package/dist/llmock.d.ts +70 -0
- package/dist/llmock.d.ts.map +1 -0
- package/dist/llmock.js +223 -0
- package/dist/llmock.js.map +1 -0
- package/dist/logger.cjs +29 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +14 -0
- package/dist/logger.d.cts.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-handler.cjs +189 -0
- package/dist/mcp-handler.cjs.map +1 -0
- package/dist/mcp-handler.js +188 -0
- package/dist/mcp-handler.js.map +1 -0
- package/dist/mcp-mock.cjs +169 -0
- package/dist/mcp-mock.cjs.map +1 -0
- package/dist/mcp-mock.d.cts +40 -0
- package/dist/mcp-mock.d.cts.map +1 -0
- package/dist/mcp-mock.d.ts +40 -0
- package/dist/mcp-mock.d.ts.map +1 -0
- package/dist/mcp-mock.js +167 -0
- package/dist/mcp-mock.js.map +1 -0
- package/dist/mcp-stub.cjs +4 -0
- package/dist/mcp-stub.d.cts +3 -0
- package/dist/mcp-stub.d.ts +3 -0
- package/dist/mcp-stub.js +3 -0
- package/dist/mcp-types.d.cts +65 -0
- package/dist/mcp-types.d.cts.map +1 -0
- package/dist/mcp-types.d.ts +65 -0
- package/dist/mcp-types.d.ts.map +1 -0
- package/dist/messages.cjs +489 -0
- package/dist/messages.cjs.map +1 -0
- package/dist/messages.d.cts +10 -0
- package/dist/messages.d.cts.map +1 -0
- package/dist/messages.d.ts +10 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +489 -0
- package/dist/messages.js.map +1 -0
- package/dist/metrics.cjs +160 -0
- package/dist/metrics.cjs.map +1 -0
- package/dist/metrics.d.cts +24 -0
- package/dist/metrics.d.cts.map +1 -0
- package/dist/metrics.d.ts +24 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +158 -0
- package/dist/metrics.js.map +1 -0
- package/dist/moderation.cjs +91 -0
- package/dist/moderation.cjs.map +1 -0
- package/dist/moderation.d.cts +23 -0
- package/dist/moderation.d.cts.map +1 -0
- package/dist/moderation.d.ts +23 -0
- package/dist/moderation.d.ts.map +1 -0
- package/dist/moderation.js +91 -0
- package/dist/moderation.js.map +1 -0
- package/dist/ndjson-writer.cjs +31 -0
- package/dist/ndjson-writer.cjs.map +1 -0
- package/dist/ndjson-writer.d.cts +17 -0
- package/dist/ndjson-writer.d.cts.map +1 -0
- package/dist/ndjson-writer.d.ts +17 -0
- package/dist/ndjson-writer.d.ts.map +1 -0
- package/dist/ndjson-writer.js +31 -0
- package/dist/ndjson-writer.js.map +1 -0
- package/dist/ollama.cjs +519 -0
- package/dist/ollama.cjs.map +1 -0
- package/dist/ollama.d.cts +34 -0
- package/dist/ollama.d.cts.map +1 -0
- package/dist/ollama.d.ts +34 -0
- package/dist/ollama.d.ts.map +1 -0
- package/dist/ollama.js +517 -0
- package/dist/ollama.js.map +1 -0
- package/dist/recorder.cjs +311 -0
- package/dist/recorder.cjs.map +1 -0
- package/dist/recorder.d.cts +23 -0
- package/dist/recorder.d.cts.map +1 -0
- package/dist/recorder.d.ts +23 -0
- package/dist/recorder.d.ts.map +1 -0
- package/dist/recorder.js +305 -0
- package/dist/recorder.js.map +1 -0
- package/dist/rerank.cjs +71 -0
- package/dist/rerank.cjs.map +1 -0
- package/dist/rerank.d.cts +22 -0
- package/dist/rerank.d.cts.map +1 -0
- package/dist/rerank.d.ts +22 -0
- package/dist/rerank.d.ts.map +1 -0
- package/dist/rerank.js +71 -0
- package/dist/rerank.js.map +1 -0
- package/dist/responses.cjs +637 -0
- package/dist/responses.cjs.map +1 -0
- package/dist/responses.d.cts +16 -0
- package/dist/responses.d.cts.map +1 -0
- package/dist/responses.d.ts +16 -0
- package/dist/responses.d.ts.map +1 -0
- package/dist/responses.js +634 -0
- package/dist/responses.js.map +1 -0
- package/dist/router.cjs +68 -0
- package/dist/router.cjs.map +1 -0
- package/dist/router.d.cts +16 -0
- package/dist/router.d.cts.map +1 -0
- package/dist/router.d.ts +16 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +65 -0
- package/dist/router.js.map +1 -0
- package/dist/search.cjs +59 -0
- package/dist/search.cjs.map +1 -0
- package/dist/search.d.cts +23 -0
- package/dist/search.d.cts.map +1 -0
- package/dist/search.d.ts +23 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +59 -0
- package/dist/search.js.map +1 -0
- package/dist/server.cjs +935 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +28 -0
- package/dist/server.d.cts.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +933 -0
- package/dist/server.js.map +1 -0
- package/dist/sse-writer.cjs +59 -0
- package/dist/sse-writer.cjs.map +1 -0
- package/dist/sse-writer.d.cts +19 -0
- package/dist/sse-writer.d.cts.map +1 -0
- package/dist/sse-writer.d.ts +19 -0
- package/dist/sse-writer.d.ts.map +1 -0
- package/dist/sse-writer.js +55 -0
- package/dist/sse-writer.js.map +1 -0
- package/dist/stream-collapse.cjs +496 -0
- package/dist/stream-collapse.cjs.map +1 -0
- package/dist/stream-collapse.d.cts +70 -0
- package/dist/stream-collapse.d.cts.map +1 -0
- package/dist/stream-collapse.d.ts +70 -0
- package/dist/stream-collapse.d.ts.map +1 -0
- package/dist/stream-collapse.js +489 -0
- package/dist/stream-collapse.js.map +1 -0
- package/dist/suite.cjs +46 -0
- package/dist/suite.cjs.map +1 -0
- package/dist/suite.d.cts +31 -0
- package/dist/suite.d.cts.map +1 -0
- package/dist/suite.d.ts +31 -0
- package/dist/suite.d.ts.map +1 -0
- package/dist/suite.js +46 -0
- package/dist/suite.js.map +1 -0
- package/dist/types.d.cts +243 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/url.cjs +21 -0
- package/dist/url.cjs.map +1 -0
- package/dist/url.d.cts +16 -0
- package/dist/url.d.cts.map +1 -0
- package/dist/url.d.ts +16 -0
- package/dist/url.d.ts.map +1 -0
- package/dist/url.js +20 -0
- package/dist/url.js.map +1 -0
- package/dist/vector-handler.cjs +239 -0
- package/dist/vector-handler.cjs.map +1 -0
- package/dist/vector-handler.js +238 -0
- package/dist/vector-handler.js.map +1 -0
- package/dist/vector-mock.cjs +229 -0
- package/dist/vector-mock.cjs.map +1 -0
- package/dist/vector-mock.d.cts +39 -0
- package/dist/vector-mock.d.cts.map +1 -0
- package/dist/vector-mock.d.ts +39 -0
- package/dist/vector-mock.d.ts.map +1 -0
- package/dist/vector-mock.js +227 -0
- package/dist/vector-mock.js.map +1 -0
- package/dist/vector-stub.cjs +4 -0
- package/dist/vector-stub.d.cts +3 -0
- package/dist/vector-stub.d.ts +3 -0
- package/dist/vector-stub.js +3 -0
- package/dist/vector-types.d.cts +32 -0
- package/dist/vector-types.d.cts.map +1 -0
- package/dist/vector-types.d.ts +32 -0
- package/dist/vector-types.d.ts.map +1 -0
- package/dist/watcher.cjs +59 -0
- package/dist/watcher.cjs.map +1 -0
- package/dist/watcher.js +58 -0
- package/dist/watcher.js.map +1 -0
- package/dist/ws-framing.cjs +187 -0
- package/dist/ws-framing.cjs.map +1 -0
- package/dist/ws-framing.d.cts +26 -0
- package/dist/ws-framing.d.cts.map +1 -0
- package/dist/ws-framing.d.ts +26 -0
- package/dist/ws-framing.d.ts.map +1 -0
- package/dist/ws-framing.js +184 -0
- package/dist/ws-framing.js.map +1 -0
- package/dist/ws-gemini-live.cjs +364 -0
- package/dist/ws-gemini-live.cjs.map +1 -0
- package/dist/ws-gemini-live.d.cts +18 -0
- package/dist/ws-gemini-live.d.cts.map +1 -0
- package/dist/ws-gemini-live.d.ts +18 -0
- package/dist/ws-gemini-live.d.ts.map +1 -0
- package/dist/ws-gemini-live.js +364 -0
- package/dist/ws-gemini-live.js.map +1 -0
- package/dist/ws-realtime.cjs +435 -0
- package/dist/ws-realtime.cjs.map +1 -0
- package/dist/ws-realtime.d.cts +17 -0
- package/dist/ws-realtime.d.cts.map +1 -0
- package/dist/ws-realtime.d.ts +17 -0
- package/dist/ws-realtime.d.ts.map +1 -0
- package/dist/ws-realtime.js +435 -0
- package/dist/ws-realtime.js.map +1 -0
- package/dist/ws-responses.cjs +164 -0
- package/dist/ws-responses.cjs.map +1 -0
- package/dist/ws-responses.d.cts +18 -0
- package/dist/ws-responses.d.cts.map +1 -0
- package/dist/ws-responses.d.ts +18 -0
- package/dist/ws-responses.d.ts.map +1 -0
- package/dist/ws-responses.js +164 -0
- package/dist/ws-responses.js.map +1 -0
- package/fixtures/example-greeting.json +12 -0
- package/fixtures/example-multi-turn.json +14 -0
- package/fixtures/example-tool-call.json +15 -0
- package/package.json +118 -0
- package/skills/write-fixtures/SKILL.md +625 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "copilotkit-tools",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "CopilotKit"
|
|
5
|
+
},
|
|
6
|
+
"plugins": [
|
|
7
|
+
{
|
|
8
|
+
"name": "llmock",
|
|
9
|
+
"source": {
|
|
10
|
+
"source": "npm",
|
|
11
|
+
"package": "@copilotkit/aimock",
|
|
12
|
+
"version": "^1.7.0"
|
|
13
|
+
},
|
|
14
|
+
"description": "Fixture authoring skill for @copilotkit/aimock — match fields, response types, embeddings, structured output, sequential responses, streaming physics, agent loop patterns, gotchas, and debugging"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "llmock",
|
|
3
|
+
"version": "1.7.0",
|
|
4
|
+
"description": "Fixture authoring guidance for @copilotkit/aimock",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "CopilotKit"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/CopilotKit/llmock",
|
|
9
|
+
"repository": "https://github.com/CopilotKit/llmock",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"skills": "./skills"
|
|
12
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CopilotKit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# aimock [](https://github.com/CopilotKit/llmock/actions/workflows/test-unit.yml) [](https://github.com/CopilotKit/llmock/actions/workflows/test-drift.yml) [](https://www.npmjs.com/package/@copilotkit/aimock)
|
|
2
|
+
|
|
3
|
+
Mock infrastructure for AI application testing — LLM APIs, MCP tools, A2A agents, vector databases, search, rerank, and moderation. One package, one port, zero dependencies.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @copilotkit/aimock
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { LLMock } from "@copilotkit/aimock";
|
|
13
|
+
|
|
14
|
+
const mock = new LLMock({ port: 0 });
|
|
15
|
+
mock.onMessage("hello", { content: "Hi there!" });
|
|
16
|
+
await mock.start();
|
|
17
|
+
|
|
18
|
+
process.env.OPENAI_BASE_URL = `${mock.url}/v1`;
|
|
19
|
+
|
|
20
|
+
// ... run your tests ...
|
|
21
|
+
|
|
22
|
+
await mock.stop();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## The aimock Suite
|
|
26
|
+
|
|
27
|
+
aimock mocks everything your AI app talks to:
|
|
28
|
+
|
|
29
|
+
| Tool | What it mocks | Docs |
|
|
30
|
+
| -------------- | ----------------------------------------------------------------- | -------------------------------------------------------- |
|
|
31
|
+
| **LLMock** | OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere | [Providers](https://aimock.copilotkit.dev/docs.html) |
|
|
32
|
+
| **MCPMock** | MCP tools, resources, prompts with session management | [MCP](https://aimock.copilotkit.dev/mcp-mock.html) |
|
|
33
|
+
| **A2AMock** | Agent-to-agent protocol with SSE streaming | [A2A](https://aimock.copilotkit.dev/a2a-mock.html) |
|
|
34
|
+
| **VectorMock** | Pinecone, Qdrant, ChromaDB compatible endpoints | [Vector](https://aimock.copilotkit.dev/vector-mock.html) |
|
|
35
|
+
| **Services** | Tavily search, Cohere rerank, OpenAI moderation | [Services](https://aimock.copilotkit.dev/services.html) |
|
|
36
|
+
|
|
37
|
+
Run them all on one port with `npx aimock --config aimock.json`, or use the programmatic API to compose exactly what you need.
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **[Record & Replay](https://aimock.copilotkit.dev/record-replay.html)** — Proxy real APIs, save as fixtures, replay deterministically forever
|
|
42
|
+
- **[11 LLM Providers](https://aimock.copilotkit.dev/docs.html)** — OpenAI, Claude, Gemini, Bedrock, Azure, Vertex AI, Ollama, Cohere — full streaming support
|
|
43
|
+
- **[MCP / A2A / Vector](https://aimock.copilotkit.dev/mcp-mock.html)** — Mock every protocol your AI agents use
|
|
44
|
+
- **[Chaos Testing](https://aimock.copilotkit.dev/chaos-testing.html)** — 500 errors, malformed JSON, mid-stream disconnects at any probability
|
|
45
|
+
- **[Drift Detection](https://aimock.copilotkit.dev/drift-detection.html)** — Daily CI validation against real APIs
|
|
46
|
+
- **[Streaming Physics](https://aimock.copilotkit.dev/streaming-physics.html)** — Configurable `ttft`, `tps`, and `jitter`
|
|
47
|
+
- **[WebSocket APIs](https://aimock.copilotkit.dev/websocket.html)** — OpenAI Realtime, Responses WS, Gemini Live
|
|
48
|
+
- **[Prometheus Metrics](https://aimock.copilotkit.dev/metrics.html)** — Request counts, latencies, fixture match rates
|
|
49
|
+
- **[Docker + Helm](https://aimock.copilotkit.dev/docker.html)** — Container image and Helm chart for CI/CD
|
|
50
|
+
- **Zero dependencies** — Everything from Node.js builtins
|
|
51
|
+
|
|
52
|
+
## CLI
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# LLM mocking only
|
|
56
|
+
npx aimock -p 4010 -f ./fixtures
|
|
57
|
+
|
|
58
|
+
# Full suite from config
|
|
59
|
+
npx aimock --config aimock.json
|
|
60
|
+
|
|
61
|
+
# Record mode: proxy to real APIs, save fixtures
|
|
62
|
+
npx aimock --record --provider-openai https://api.openai.com
|
|
63
|
+
|
|
64
|
+
# Docker
|
|
65
|
+
docker run -d -p 4010:4010 -v ./fixtures:/fixtures ghcr.io/copilotkit/aimock -f /fixtures
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Switching from other tools?
|
|
69
|
+
|
|
70
|
+
Step-by-step migration guides: [MSW](https://aimock.copilotkit.dev/migrate-from-msw.html) · [VidaiMock](https://aimock.copilotkit.dev/migrate-from-vidaimock.html) · [mock-llm](https://aimock.copilotkit.dev/migrate-from-mock-llm.html) · [Python mocks](https://aimock.copilotkit.dev/migrate-from-python-mocks.html) · [Mokksy](https://aimock.copilotkit.dev/migrate-from-mokksy.html)
|
|
71
|
+
|
|
72
|
+
## Documentation
|
|
73
|
+
|
|
74
|
+
**[https://aimock.copilotkit.dev](https://aimock.copilotkit.dev)**
|
|
75
|
+
|
|
76
|
+
## Real-World Usage
|
|
77
|
+
|
|
78
|
+
[AG-UI](https://github.com/ag-ui-protocol/ag-ui) uses aimock for its [end-to-end test suite](https://github.com/ag-ui-protocol/ag-ui/tree/main/apps/dojo/e2e), verifying AI agent behavior across LLM providers with [fixture-driven responses](https://github.com/ag-ui-protocol/ag-ui/tree/main/apps/dojo/e2e/fixtures/openai).
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
MIT
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
|
|
29
|
+
exports.__toESM = __toESM;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
const require_helpers = require('./helpers.cjs');
|
|
2
|
+
|
|
3
|
+
//#region src/a2a-handler.ts
|
|
4
|
+
function extractText(params) {
|
|
5
|
+
const p = params;
|
|
6
|
+
if (!p?.message) return "";
|
|
7
|
+
const parts = p.message.parts;
|
|
8
|
+
if (!Array.isArray(parts)) return "";
|
|
9
|
+
return parts.filter((part) => typeof part.text === "string").map((part) => part.text).join(" ");
|
|
10
|
+
}
|
|
11
|
+
function matchPattern(text, pattern) {
|
|
12
|
+
if (typeof pattern === "string") return text.includes(pattern);
|
|
13
|
+
return pattern.test(text);
|
|
14
|
+
}
|
|
15
|
+
const TERMINAL_STATES = new Set([
|
|
16
|
+
"TASK_STATE_COMPLETED",
|
|
17
|
+
"TASK_STATE_FAILED",
|
|
18
|
+
"TASK_STATE_CANCELED"
|
|
19
|
+
]);
|
|
20
|
+
function buildAgentCard(agents, baseUrl) {
|
|
21
|
+
const def = agents.values().next().value?.def;
|
|
22
|
+
return {
|
|
23
|
+
name: def?.name ?? "a2a-mock",
|
|
24
|
+
description: def?.description ?? "A2A mock agent",
|
|
25
|
+
version: def?.version ?? "1.0.0",
|
|
26
|
+
supportedInterfaces: [{
|
|
27
|
+
url: baseUrl,
|
|
28
|
+
protocolBinding: "JSONRPC",
|
|
29
|
+
protocolVersion: "1.0"
|
|
30
|
+
}],
|
|
31
|
+
skills: def?.skills ?? [],
|
|
32
|
+
capabilities: def?.capabilities ?? { streaming: true }
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function createA2AMethods(agents, tasks) {
|
|
36
|
+
function findMatch(text) {
|
|
37
|
+
for (const agent of agents.values()) for (const entry of agent.patterns) if (matchPattern(text, entry.pattern)) return entry;
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function createTask(_agentName, artifacts, userParts, state = "TASK_STATE_COMPLETED") {
|
|
41
|
+
const taskId = require_helpers.generateId("task");
|
|
42
|
+
const task = {
|
|
43
|
+
id: taskId,
|
|
44
|
+
contextId: require_helpers.generateId("ctx"),
|
|
45
|
+
status: {
|
|
46
|
+
state,
|
|
47
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
48
|
+
},
|
|
49
|
+
artifacts,
|
|
50
|
+
history: [{
|
|
51
|
+
messageId: require_helpers.generateId("msg"),
|
|
52
|
+
role: "ROLE_USER",
|
|
53
|
+
parts: userParts
|
|
54
|
+
}]
|
|
55
|
+
};
|
|
56
|
+
tasks.set(taskId, task);
|
|
57
|
+
return task;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
SendMessage: async (params, id) => {
|
|
61
|
+
const text = extractText(params);
|
|
62
|
+
const entry = findMatch(text);
|
|
63
|
+
if (!entry) return {
|
|
64
|
+
jsonrpc: "2.0",
|
|
65
|
+
id,
|
|
66
|
+
error: {
|
|
67
|
+
code: -32e3,
|
|
68
|
+
message: "No matching pattern for message"
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const userParts = (params?.message)?.parts ?? [{ text }];
|
|
72
|
+
if (entry.kind === "message") return {
|
|
73
|
+
jsonrpc: "2.0",
|
|
74
|
+
id,
|
|
75
|
+
result: { message: {
|
|
76
|
+
messageId: require_helpers.generateId("msg"),
|
|
77
|
+
role: "ROLE_AGENT",
|
|
78
|
+
parts: entry.parts
|
|
79
|
+
} }
|
|
80
|
+
};
|
|
81
|
+
if (entry.kind === "task") {
|
|
82
|
+
const task = createTask(entry.agentName, entry.artifacts, userParts);
|
|
83
|
+
return {
|
|
84
|
+
jsonrpc: "2.0",
|
|
85
|
+
id,
|
|
86
|
+
result: { task: {
|
|
87
|
+
id: task.id,
|
|
88
|
+
contextId: task.contextId,
|
|
89
|
+
status: task.status,
|
|
90
|
+
artifacts: task.artifacts
|
|
91
|
+
} }
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (entry.kind === "streamingTask") {
|
|
95
|
+
const artifacts = [];
|
|
96
|
+
for (const evt of entry.events) if (evt.type === "artifact") artifacts.push({
|
|
97
|
+
parts: evt.parts,
|
|
98
|
+
name: evt.name
|
|
99
|
+
});
|
|
100
|
+
const task = createTask(entry.agentName, artifacts, userParts);
|
|
101
|
+
return {
|
|
102
|
+
jsonrpc: "2.0",
|
|
103
|
+
id,
|
|
104
|
+
result: { task: {
|
|
105
|
+
id: task.id,
|
|
106
|
+
contextId: task.contextId,
|
|
107
|
+
status: task.status,
|
|
108
|
+
artifacts: task.artifacts
|
|
109
|
+
} }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
jsonrpc: "2.0",
|
|
114
|
+
id,
|
|
115
|
+
error: {
|
|
116
|
+
code: -32e3,
|
|
117
|
+
message: "No matching pattern for message"
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
SendStreamingMessage: async (params, id) => {
|
|
122
|
+
if (!findMatch(extractText(params))) return {
|
|
123
|
+
jsonrpc: "2.0",
|
|
124
|
+
id,
|
|
125
|
+
error: {
|
|
126
|
+
code: -32e3,
|
|
127
|
+
message: "No matching pattern for message"
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return null;
|
|
131
|
+
},
|
|
132
|
+
GetTask: async (params, id) => {
|
|
133
|
+
const taskId = params?.id;
|
|
134
|
+
if (!taskId || !tasks.has(taskId)) return {
|
|
135
|
+
jsonrpc: "2.0",
|
|
136
|
+
id,
|
|
137
|
+
error: {
|
|
138
|
+
code: -32001,
|
|
139
|
+
message: "Task not found"
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
jsonrpc: "2.0",
|
|
144
|
+
id,
|
|
145
|
+
result: { task: tasks.get(taskId) }
|
|
146
|
+
};
|
|
147
|
+
},
|
|
148
|
+
ListTasks: async (params, id) => {
|
|
149
|
+
const p = params;
|
|
150
|
+
const contextId = p?.contextId;
|
|
151
|
+
const status = p?.status;
|
|
152
|
+
let results = Array.from(tasks.values());
|
|
153
|
+
if (contextId) results = results.filter((t) => t.contextId === contextId);
|
|
154
|
+
if (status) results = results.filter((t) => t.status.state === status);
|
|
155
|
+
return {
|
|
156
|
+
jsonrpc: "2.0",
|
|
157
|
+
id,
|
|
158
|
+
result: { tasks: results }
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
CancelTask: async (params, id) => {
|
|
162
|
+
const taskId = params?.id;
|
|
163
|
+
if (!taskId || !tasks.has(taskId)) return {
|
|
164
|
+
jsonrpc: "2.0",
|
|
165
|
+
id,
|
|
166
|
+
error: {
|
|
167
|
+
code: -32001,
|
|
168
|
+
message: "Task not found"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const task = tasks.get(taskId);
|
|
172
|
+
if (TERMINAL_STATES.has(task.status.state)) return {
|
|
173
|
+
jsonrpc: "2.0",
|
|
174
|
+
id,
|
|
175
|
+
error: {
|
|
176
|
+
code: -32002,
|
|
177
|
+
message: "Task already in terminal state"
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
task.status = {
|
|
181
|
+
state: "TASK_STATE_CANCELED",
|
|
182
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
183
|
+
};
|
|
184
|
+
return {
|
|
185
|
+
jsonrpc: "2.0",
|
|
186
|
+
id,
|
|
187
|
+
result: { task }
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function findStreamingMatch(text, agents) {
|
|
193
|
+
for (const agent of agents.values()) for (const entry of agent.patterns) if (entry.kind === "streamingTask" && matchPattern(text, entry.pattern)) return entry;
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
exports.TERMINAL_STATES = TERMINAL_STATES;
|
|
199
|
+
exports.buildAgentCard = buildAgentCard;
|
|
200
|
+
exports.createA2AMethods = createA2AMethods;
|
|
201
|
+
exports.extractText = extractText;
|
|
202
|
+
exports.findStreamingMatch = findStreamingMatch;
|
|
203
|
+
//# sourceMappingURL=a2a-handler.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-handler.cjs","names":["generateId"],"sources":["../src/a2a-handler.ts"],"sourcesContent":["import type { JsonRpcResponse, MethodHandler } from \"./jsonrpc.js\";\nimport type {\n A2AAgentDefinition,\n A2AArtifact,\n A2APart,\n A2AStreamEvent,\n A2ATask,\n A2ATaskState,\n} from \"./a2a-types.js\";\nimport { generateId } from \"./helpers.js\";\n\n// ---- Pattern types ----\n\nexport interface MessagePatternEntry {\n kind: \"message\";\n pattern: string | RegExp;\n agentName: string;\n parts: A2APart[];\n}\n\nexport interface TaskPatternEntry {\n kind: \"task\";\n pattern: string | RegExp;\n agentName: string;\n artifacts: A2AArtifact[];\n}\n\nexport interface StreamingTaskPatternEntry {\n kind: \"streamingTask\";\n pattern: string | RegExp;\n agentName: string;\n events: A2AStreamEvent[];\n delayMs?: number;\n}\n\nexport type PatternEntry = MessagePatternEntry | TaskPatternEntry | StreamingTaskPatternEntry;\n\n// ---- Helpers ----\n\nfunction extractText(params: unknown): string {\n const p = params as Record<string, unknown> | undefined;\n if (!p?.message) return \"\";\n const msg = p.message as Record<string, unknown>;\n const parts = msg.parts as Array<Record<string, unknown>> | undefined;\n if (!Array.isArray(parts)) return \"\";\n return parts\n .filter((part) => typeof part.text === \"string\")\n .map((part) => part.text as string)\n .join(\" \");\n}\n\nfunction matchPattern(text: string, pattern: string | RegExp): boolean {\n if (typeof pattern === \"string\") {\n return text.includes(pattern);\n }\n return pattern.test(text);\n}\n\nexport const TERMINAL_STATES: Set<string> = new Set([\n \"TASK_STATE_COMPLETED\",\n \"TASK_STATE_FAILED\",\n \"TASK_STATE_CANCELED\",\n]);\n\n// ---- Agent card builder ----\n\nexport function buildAgentCard(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n baseUrl: string,\n): Record<string, unknown> {\n // Use the first registered agent as the primary card, or a default\n const first = agents.values().next().value;\n const def = first?.def;\n\n return {\n name: def?.name ?? \"a2a-mock\",\n description: def?.description ?? \"A2A mock agent\",\n version: def?.version ?? \"1.0.0\",\n supportedInterfaces: [\n {\n url: baseUrl,\n protocolBinding: \"JSONRPC\",\n protocolVersion: \"1.0\",\n },\n ],\n skills: def?.skills ?? [],\n capabilities: def?.capabilities ?? { streaming: true },\n };\n}\n\n// ---- Method handlers ----\n\nexport function createA2AMethods(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n tasks: Map<string, A2ATask>,\n): Record<string, MethodHandler> {\n function findMatch(text: string): PatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n }\n\n function createTask(\n _agentName: string,\n artifacts: A2AArtifact[],\n userParts: A2APart[],\n state: A2ATaskState = \"TASK_STATE_COMPLETED\",\n ): A2ATask {\n const taskId = generateId(\"task\");\n const contextId = generateId(\"ctx\");\n const task: A2ATask = {\n id: taskId,\n contextId,\n status: { state, timestamp: new Date().toISOString() },\n artifacts,\n history: [\n {\n messageId: generateId(\"msg\"),\n role: \"ROLE_USER\",\n parts: userParts,\n },\n ],\n };\n tasks.set(taskId, task);\n return task;\n }\n\n const methods: Record<string, MethodHandler> = {\n SendMessage: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const text = extractText(params);\n const entry = findMatch(text);\n\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n\n const p = params as Record<string, unknown> | undefined;\n const msg = p?.message as Record<string, unknown> | undefined;\n const userParts: A2APart[] = (msg?.parts as A2APart[]) ?? [{ text }];\n\n if (entry.kind === \"message\") {\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n message: {\n messageId: generateId(\"msg\"),\n role: \"ROLE_AGENT\",\n parts: entry.parts,\n },\n },\n };\n }\n\n if (entry.kind === \"task\") {\n const task = createTask(entry.agentName, entry.artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n // streamingTask patterns matched via SendMessage just return task\n if (entry.kind === \"streamingTask\") {\n const artifacts: A2AArtifact[] = [];\n for (const evt of entry.events) {\n if (evt.type === \"artifact\") {\n artifacts.push({ parts: evt.parts, name: evt.name });\n }\n }\n const task = createTask(entry.agentName, artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n },\n\n // SendStreamingMessage is handled specially in A2AMock (SSE response),\n // but we register a placeholder so the dispatcher doesn't return \"method not found\".\n SendStreamingMessage: async (\n params: unknown,\n id: string | number,\n ): Promise<JsonRpcResponse | null> => {\n // This is intercepted before reaching the dispatcher in a2a-mock.ts\n // If it reaches here, return an error\n const text = extractText(params);\n const entry = findMatch(text);\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n return null;\n },\n\n GetTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task: tasks.get(taskId) },\n };\n },\n\n ListTasks: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const contextId = p?.contextId as string | undefined;\n const status = p?.status as string | undefined;\n\n let results = Array.from(tasks.values());\n\n if (contextId) {\n results = results.filter((t) => t.contextId === contextId);\n }\n if (status) {\n results = results.filter((t) => t.status.state === status);\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { tasks: results },\n };\n },\n\n CancelTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n const task = tasks.get(taskId)!;\n\n if (TERMINAL_STATES.has(task.status.state)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32002, message: \"Task already in terminal state\" },\n };\n }\n\n task.status = {\n state: \"TASK_STATE_CANCELED\",\n timestamp: new Date().toISOString(),\n };\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task },\n };\n },\n };\n\n return methods;\n}\n\n// ---- Streaming helpers ----\n\nexport function findStreamingMatch(\n text: string,\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n): StreamingTaskPatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (entry.kind === \"streamingTask\" && matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n}\n\nexport { extractText };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { generateId } from "./helpers.js";
|
|
2
|
+
|
|
3
|
+
//#region src/a2a-handler.ts
|
|
4
|
+
function extractText(params) {
|
|
5
|
+
const p = params;
|
|
6
|
+
if (!p?.message) return "";
|
|
7
|
+
const parts = p.message.parts;
|
|
8
|
+
if (!Array.isArray(parts)) return "";
|
|
9
|
+
return parts.filter((part) => typeof part.text === "string").map((part) => part.text).join(" ");
|
|
10
|
+
}
|
|
11
|
+
function matchPattern(text, pattern) {
|
|
12
|
+
if (typeof pattern === "string") return text.includes(pattern);
|
|
13
|
+
return pattern.test(text);
|
|
14
|
+
}
|
|
15
|
+
const TERMINAL_STATES = new Set([
|
|
16
|
+
"TASK_STATE_COMPLETED",
|
|
17
|
+
"TASK_STATE_FAILED",
|
|
18
|
+
"TASK_STATE_CANCELED"
|
|
19
|
+
]);
|
|
20
|
+
function buildAgentCard(agents, baseUrl) {
|
|
21
|
+
const def = agents.values().next().value?.def;
|
|
22
|
+
return {
|
|
23
|
+
name: def?.name ?? "a2a-mock",
|
|
24
|
+
description: def?.description ?? "A2A mock agent",
|
|
25
|
+
version: def?.version ?? "1.0.0",
|
|
26
|
+
supportedInterfaces: [{
|
|
27
|
+
url: baseUrl,
|
|
28
|
+
protocolBinding: "JSONRPC",
|
|
29
|
+
protocolVersion: "1.0"
|
|
30
|
+
}],
|
|
31
|
+
skills: def?.skills ?? [],
|
|
32
|
+
capabilities: def?.capabilities ?? { streaming: true }
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function createA2AMethods(agents, tasks) {
|
|
36
|
+
function findMatch(text) {
|
|
37
|
+
for (const agent of agents.values()) for (const entry of agent.patterns) if (matchPattern(text, entry.pattern)) return entry;
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function createTask(_agentName, artifacts, userParts, state = "TASK_STATE_COMPLETED") {
|
|
41
|
+
const taskId = generateId("task");
|
|
42
|
+
const task = {
|
|
43
|
+
id: taskId,
|
|
44
|
+
contextId: generateId("ctx"),
|
|
45
|
+
status: {
|
|
46
|
+
state,
|
|
47
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
48
|
+
},
|
|
49
|
+
artifacts,
|
|
50
|
+
history: [{
|
|
51
|
+
messageId: generateId("msg"),
|
|
52
|
+
role: "ROLE_USER",
|
|
53
|
+
parts: userParts
|
|
54
|
+
}]
|
|
55
|
+
};
|
|
56
|
+
tasks.set(taskId, task);
|
|
57
|
+
return task;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
SendMessage: async (params, id) => {
|
|
61
|
+
const text = extractText(params);
|
|
62
|
+
const entry = findMatch(text);
|
|
63
|
+
if (!entry) return {
|
|
64
|
+
jsonrpc: "2.0",
|
|
65
|
+
id,
|
|
66
|
+
error: {
|
|
67
|
+
code: -32e3,
|
|
68
|
+
message: "No matching pattern for message"
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const userParts = (params?.message)?.parts ?? [{ text }];
|
|
72
|
+
if (entry.kind === "message") return {
|
|
73
|
+
jsonrpc: "2.0",
|
|
74
|
+
id,
|
|
75
|
+
result: { message: {
|
|
76
|
+
messageId: generateId("msg"),
|
|
77
|
+
role: "ROLE_AGENT",
|
|
78
|
+
parts: entry.parts
|
|
79
|
+
} }
|
|
80
|
+
};
|
|
81
|
+
if (entry.kind === "task") {
|
|
82
|
+
const task = createTask(entry.agentName, entry.artifacts, userParts);
|
|
83
|
+
return {
|
|
84
|
+
jsonrpc: "2.0",
|
|
85
|
+
id,
|
|
86
|
+
result: { task: {
|
|
87
|
+
id: task.id,
|
|
88
|
+
contextId: task.contextId,
|
|
89
|
+
status: task.status,
|
|
90
|
+
artifacts: task.artifacts
|
|
91
|
+
} }
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (entry.kind === "streamingTask") {
|
|
95
|
+
const artifacts = [];
|
|
96
|
+
for (const evt of entry.events) if (evt.type === "artifact") artifacts.push({
|
|
97
|
+
parts: evt.parts,
|
|
98
|
+
name: evt.name
|
|
99
|
+
});
|
|
100
|
+
const task = createTask(entry.agentName, artifacts, userParts);
|
|
101
|
+
return {
|
|
102
|
+
jsonrpc: "2.0",
|
|
103
|
+
id,
|
|
104
|
+
result: { task: {
|
|
105
|
+
id: task.id,
|
|
106
|
+
contextId: task.contextId,
|
|
107
|
+
status: task.status,
|
|
108
|
+
artifacts: task.artifacts
|
|
109
|
+
} }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
jsonrpc: "2.0",
|
|
114
|
+
id,
|
|
115
|
+
error: {
|
|
116
|
+
code: -32e3,
|
|
117
|
+
message: "No matching pattern for message"
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
SendStreamingMessage: async (params, id) => {
|
|
122
|
+
if (!findMatch(extractText(params))) return {
|
|
123
|
+
jsonrpc: "2.0",
|
|
124
|
+
id,
|
|
125
|
+
error: {
|
|
126
|
+
code: -32e3,
|
|
127
|
+
message: "No matching pattern for message"
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
return null;
|
|
131
|
+
},
|
|
132
|
+
GetTask: async (params, id) => {
|
|
133
|
+
const taskId = params?.id;
|
|
134
|
+
if (!taskId || !tasks.has(taskId)) return {
|
|
135
|
+
jsonrpc: "2.0",
|
|
136
|
+
id,
|
|
137
|
+
error: {
|
|
138
|
+
code: -32001,
|
|
139
|
+
message: "Task not found"
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
return {
|
|
143
|
+
jsonrpc: "2.0",
|
|
144
|
+
id,
|
|
145
|
+
result: { task: tasks.get(taskId) }
|
|
146
|
+
};
|
|
147
|
+
},
|
|
148
|
+
ListTasks: async (params, id) => {
|
|
149
|
+
const p = params;
|
|
150
|
+
const contextId = p?.contextId;
|
|
151
|
+
const status = p?.status;
|
|
152
|
+
let results = Array.from(tasks.values());
|
|
153
|
+
if (contextId) results = results.filter((t) => t.contextId === contextId);
|
|
154
|
+
if (status) results = results.filter((t) => t.status.state === status);
|
|
155
|
+
return {
|
|
156
|
+
jsonrpc: "2.0",
|
|
157
|
+
id,
|
|
158
|
+
result: { tasks: results }
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
CancelTask: async (params, id) => {
|
|
162
|
+
const taskId = params?.id;
|
|
163
|
+
if (!taskId || !tasks.has(taskId)) return {
|
|
164
|
+
jsonrpc: "2.0",
|
|
165
|
+
id,
|
|
166
|
+
error: {
|
|
167
|
+
code: -32001,
|
|
168
|
+
message: "Task not found"
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const task = tasks.get(taskId);
|
|
172
|
+
if (TERMINAL_STATES.has(task.status.state)) return {
|
|
173
|
+
jsonrpc: "2.0",
|
|
174
|
+
id,
|
|
175
|
+
error: {
|
|
176
|
+
code: -32002,
|
|
177
|
+
message: "Task already in terminal state"
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
task.status = {
|
|
181
|
+
state: "TASK_STATE_CANCELED",
|
|
182
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
183
|
+
};
|
|
184
|
+
return {
|
|
185
|
+
jsonrpc: "2.0",
|
|
186
|
+
id,
|
|
187
|
+
result: { task }
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function findStreamingMatch(text, agents) {
|
|
193
|
+
for (const agent of agents.values()) for (const entry of agent.patterns) if (entry.kind === "streamingTask" && matchPattern(text, entry.pattern)) return entry;
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
export { TERMINAL_STATES, buildAgentCard, createA2AMethods, extractText, findStreamingMatch };
|
|
199
|
+
//# sourceMappingURL=a2a-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"a2a-handler.js","names":[],"sources":["../src/a2a-handler.ts"],"sourcesContent":["import type { JsonRpcResponse, MethodHandler } from \"./jsonrpc.js\";\nimport type {\n A2AAgentDefinition,\n A2AArtifact,\n A2APart,\n A2AStreamEvent,\n A2ATask,\n A2ATaskState,\n} from \"./a2a-types.js\";\nimport { generateId } from \"./helpers.js\";\n\n// ---- Pattern types ----\n\nexport interface MessagePatternEntry {\n kind: \"message\";\n pattern: string | RegExp;\n agentName: string;\n parts: A2APart[];\n}\n\nexport interface TaskPatternEntry {\n kind: \"task\";\n pattern: string | RegExp;\n agentName: string;\n artifacts: A2AArtifact[];\n}\n\nexport interface StreamingTaskPatternEntry {\n kind: \"streamingTask\";\n pattern: string | RegExp;\n agentName: string;\n events: A2AStreamEvent[];\n delayMs?: number;\n}\n\nexport type PatternEntry = MessagePatternEntry | TaskPatternEntry | StreamingTaskPatternEntry;\n\n// ---- Helpers ----\n\nfunction extractText(params: unknown): string {\n const p = params as Record<string, unknown> | undefined;\n if (!p?.message) return \"\";\n const msg = p.message as Record<string, unknown>;\n const parts = msg.parts as Array<Record<string, unknown>> | undefined;\n if (!Array.isArray(parts)) return \"\";\n return parts\n .filter((part) => typeof part.text === \"string\")\n .map((part) => part.text as string)\n .join(\" \");\n}\n\nfunction matchPattern(text: string, pattern: string | RegExp): boolean {\n if (typeof pattern === \"string\") {\n return text.includes(pattern);\n }\n return pattern.test(text);\n}\n\nexport const TERMINAL_STATES: Set<string> = new Set([\n \"TASK_STATE_COMPLETED\",\n \"TASK_STATE_FAILED\",\n \"TASK_STATE_CANCELED\",\n]);\n\n// ---- Agent card builder ----\n\nexport function buildAgentCard(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n baseUrl: string,\n): Record<string, unknown> {\n // Use the first registered agent as the primary card, or a default\n const first = agents.values().next().value;\n const def = first?.def;\n\n return {\n name: def?.name ?? \"a2a-mock\",\n description: def?.description ?? \"A2A mock agent\",\n version: def?.version ?? \"1.0.0\",\n supportedInterfaces: [\n {\n url: baseUrl,\n protocolBinding: \"JSONRPC\",\n protocolVersion: \"1.0\",\n },\n ],\n skills: def?.skills ?? [],\n capabilities: def?.capabilities ?? { streaming: true },\n };\n}\n\n// ---- Method handlers ----\n\nexport function createA2AMethods(\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n tasks: Map<string, A2ATask>,\n): Record<string, MethodHandler> {\n function findMatch(text: string): PatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n }\n\n function createTask(\n _agentName: string,\n artifacts: A2AArtifact[],\n userParts: A2APart[],\n state: A2ATaskState = \"TASK_STATE_COMPLETED\",\n ): A2ATask {\n const taskId = generateId(\"task\");\n const contextId = generateId(\"ctx\");\n const task: A2ATask = {\n id: taskId,\n contextId,\n status: { state, timestamp: new Date().toISOString() },\n artifacts,\n history: [\n {\n messageId: generateId(\"msg\"),\n role: \"ROLE_USER\",\n parts: userParts,\n },\n ],\n };\n tasks.set(taskId, task);\n return task;\n }\n\n const methods: Record<string, MethodHandler> = {\n SendMessage: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const text = extractText(params);\n const entry = findMatch(text);\n\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n\n const p = params as Record<string, unknown> | undefined;\n const msg = p?.message as Record<string, unknown> | undefined;\n const userParts: A2APart[] = (msg?.parts as A2APart[]) ?? [{ text }];\n\n if (entry.kind === \"message\") {\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n message: {\n messageId: generateId(\"msg\"),\n role: \"ROLE_AGENT\",\n parts: entry.parts,\n },\n },\n };\n }\n\n if (entry.kind === \"task\") {\n const task = createTask(entry.agentName, entry.artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n // streamingTask patterns matched via SendMessage just return task\n if (entry.kind === \"streamingTask\") {\n const artifacts: A2AArtifact[] = [];\n for (const evt of entry.events) {\n if (evt.type === \"artifact\") {\n artifacts.push({ parts: evt.parts, name: evt.name });\n }\n }\n const task = createTask(entry.agentName, artifacts, userParts);\n return {\n jsonrpc: \"2.0\",\n id,\n result: {\n task: {\n id: task.id,\n contextId: task.contextId,\n status: task.status,\n artifacts: task.artifacts,\n },\n },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n },\n\n // SendStreamingMessage is handled specially in A2AMock (SSE response),\n // but we register a placeholder so the dispatcher doesn't return \"method not found\".\n SendStreamingMessage: async (\n params: unknown,\n id: string | number,\n ): Promise<JsonRpcResponse | null> => {\n // This is intercepted before reaching the dispatcher in a2a-mock.ts\n // If it reaches here, return an error\n const text = extractText(params);\n const entry = findMatch(text);\n if (!entry) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32000, message: \"No matching pattern for message\" },\n };\n }\n return null;\n },\n\n GetTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task: tasks.get(taskId) },\n };\n },\n\n ListTasks: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const contextId = p?.contextId as string | undefined;\n const status = p?.status as string | undefined;\n\n let results = Array.from(tasks.values());\n\n if (contextId) {\n results = results.filter((t) => t.contextId === contextId);\n }\n if (status) {\n results = results.filter((t) => t.status.state === status);\n }\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { tasks: results },\n };\n },\n\n CancelTask: async (params: unknown, id: string | number): Promise<JsonRpcResponse> => {\n const p = params as Record<string, unknown> | undefined;\n const taskId = p?.id as string | undefined;\n\n if (!taskId || !tasks.has(taskId)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32001, message: \"Task not found\" },\n };\n }\n\n const task = tasks.get(taskId)!;\n\n if (TERMINAL_STATES.has(task.status.state)) {\n return {\n jsonrpc: \"2.0\",\n id,\n error: { code: -32002, message: \"Task already in terminal state\" },\n };\n }\n\n task.status = {\n state: \"TASK_STATE_CANCELED\",\n timestamp: new Date().toISOString(),\n };\n\n return {\n jsonrpc: \"2.0\",\n id,\n result: { task },\n };\n },\n };\n\n return methods;\n}\n\n// ---- Streaming helpers ----\n\nexport function findStreamingMatch(\n text: string,\n agents: Map<string, { def: A2AAgentDefinition; patterns: PatternEntry[] }>,\n): StreamingTaskPatternEntry | null {\n for (const agent of agents.values()) {\n for (const entry of agent.patterns) {\n if (entry.kind === \"streamingTask\" && matchPattern(text, entry.pattern)) {\n return entry;\n }\n }\n }\n return null;\n}\n\nexport { extractText };\n"],"mappings":"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"}
|