@noetaris/harness-anthropic 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @noetaris/harness-anthropic
2
+
3
+ Anthropic Claude adapter for [@noetaris/harness](../core).
4
+
5
+ > **Status:** not yet released. Implementation tracked in F20.
6
+
7
+ ## Overview
8
+
9
+ `@noetaris/harness-anthropic` provides a `Claude` class that implements the `LLM` and `ObserverAware` interfaces from `@noetaris/harness`. It handles translation between the harness message format and the Anthropic SDK format, and emits telemetry events (token usage, model ID) through an attached `Observer`.
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ pnpm add @noetaris/harness-anthropic
15
+ ```
16
+
17
+ Peer dependencies:
18
+
19
+ ```sh
20
+ pnpm add @noetaris/harness @noetaris/harness-types
21
+ ```
22
+
23
+ Requires Node.js ≥ 22.
24
+
25
+ ## Usage
26
+
27
+ ```ts
28
+ import { Claude } from '@noetaris/harness-anthropic'
29
+
30
+ const llm = new Claude({ apiKey: process.env.ANTHROPIC_API_KEY })
31
+
32
+ // Wire into a harness provider slot
33
+ h.provide('model', runtime())
34
+
35
+ const agent = createAgent(h, { prompts: { system: '...' } })
36
+ const run = agent.run(initialState, { model: llm })
37
+ ```
38
+
39
+ ## API
40
+
41
+ ### `Claude`
42
+
43
+ Implements `LLM` and `ObserverAware`.
44
+
45
+ - **`invoke(messages, options?)`** — translates harness `Message[]` and `Tool[]` to Anthropic SDK format, calls `client.messages.create()`, and maps the response back to `LLMResponse`.
46
+ - **`bindObserver(observer)`** — attaches an `Observer`; after each `invoke`, emits an `"llm.response"` event with `{ tokens: { input, output }, modelId }`.
47
+
48
+ ### `MockClaude`
49
+
50
+ A deterministic test double for use in tests and demos without a real API key.
51
+
52
+ ## Related Packages
53
+
54
+ - [`@noetaris/harness`](https://github.com/noetaris-lab/harness) — core execution engine
55
+ - [`@noetaris/harness-types`](https://github.com/noetaris-lab/harness-types) — shared LLM type contract
56
+ - [`@noetaris/harness-openai`](https://github.com/noetaris-lab/harness-openai) — OpenAI adapter
57
+ - [`@noetaris/harness-google`](https://github.com/noetaris-lab/harness-google) — Google Gemini adapter
58
+ - [`@noetaris/harness-otel`](https://github.com/noetaris-lab/harness-otel) — OpenTelemetry observer bridge
59
+
60
+ ## License
61
+
62
+ MIT
@@ -0,0 +1,78 @@
1
+ import { LLM, Message, Tool, LLMResponse } from '@noetaris/harness-types';
2
+ import { ObserverAware, Observer, StepContext } from '@noetaris/harness';
3
+
4
+ /** Options for {@link Claude}. */
5
+ interface ClaudeOptions {
6
+ /** Anthropic API key. Defaults to the `ANTHROPIC_API_KEY` environment variable. */
7
+ apiKey?: string;
8
+ }
9
+ /**
10
+ * {@link LLM} adapter for the Anthropic Messages API.
11
+ *
12
+ * Implements {@link ObserverAware} — when an observer is bound the adapter
13
+ * emits an `'llm.response'` event carrying an `LLMUsageEvent` payload after
14
+ * each successful invocation.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const llm = new Claude('claude-3-5-haiku-20241022')
19
+ * const response = await llm.invoke(messages)
20
+ * ```
21
+ */
22
+ declare class Claude implements LLM, ObserverAware {
23
+ private readonly client;
24
+ private readonly model;
25
+ private observer;
26
+ private stepContext;
27
+ /**
28
+ * @param model - Anthropic model ID, e.g. `'claude-3-5-haiku-20241022'`.
29
+ * @param options - Optional API key override.
30
+ */
31
+ constructor(model: string, options?: ClaudeOptions);
32
+ bindObserver(observer: Observer): void;
33
+ setStepContext(ctx: StepContext): void;
34
+ invoke(messages: Message[], options?: {
35
+ tools?: Tool[];
36
+ }): Promise<LLMResponse>;
37
+ }
38
+
39
+ /** Thrown by {@link MockClaude} when `invoke` is called with no responses queued. */
40
+ declare class MockClaudeEmptyQueueError extends Error {
41
+ constructor();
42
+ }
43
+ /**
44
+ * In-memory test double for {@link Claude}.
45
+ *
46
+ * Pre-load one or more {@link LLMResponse} objects; each `invoke()` call
47
+ * dequeues the next response. The last response is **sticky** — once only
48
+ * one remains it repeats indefinitely rather than throwing.
49
+ *
50
+ * `lastMessages` is populated after each `invoke()` call, allowing assertions
51
+ * on the conversation history passed to the adapter.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const llm = new MockClaude({ text: 'hello', toolCalls: [], stopReason: 'end' })
56
+ * ```
57
+ */
58
+ declare class MockClaude implements LLM, ObserverAware {
59
+ /** The message list from the most recent `invoke()` call. */
60
+ lastMessages: Message[];
61
+ private queue;
62
+ private observer;
63
+ private stepContext;
64
+ /**
65
+ * @param responses - One or more responses to queue up front. May also be
66
+ * added later via {@link enqueue}.
67
+ */
68
+ constructor(responses?: LLMResponse | LLMResponse[]);
69
+ /** Add one or more responses to the end of the queue. */
70
+ enqueue(response: LLMResponse | LLMResponse[]): void;
71
+ bindObserver(observer: Observer): void;
72
+ setStepContext(ctx: StepContext): void;
73
+ invoke(messages: Message[], options?: {
74
+ tools?: Tool[];
75
+ }): Promise<LLMResponse>;
76
+ }
77
+
78
+ export { Claude, type ClaudeOptions, MockClaude, MockClaudeEmptyQueueError };
package/dist/index.js ADDED
@@ -0,0 +1,172 @@
1
+ // src/claude.ts
2
+ import Anthropic from "@anthropic-ai/sdk";
3
+ function translateMessages(messages) {
4
+ const result = [];
5
+ for (const msg of messages) {
6
+ if (msg.role === "user") {
7
+ result.push({ role: "user", content: msg.content });
8
+ } else if (msg.role === "assistant") {
9
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
10
+ const blocks = [];
11
+ if (msg.content) {
12
+ blocks.push({ type: "text", text: msg.content });
13
+ }
14
+ for (const tc of msg.toolCalls) {
15
+ blocks.push({ type: "tool_use", id: tc.id, name: tc.name, input: tc.input });
16
+ }
17
+ result.push({ role: "assistant", content: blocks });
18
+ } else {
19
+ result.push({ role: "assistant", content: msg.content ?? "" });
20
+ }
21
+ } else if (msg.role === "tool") {
22
+ const toolResultBlock = {
23
+ type: "tool_result",
24
+ tool_use_id: msg.toolCallId,
25
+ content: msg.content
26
+ };
27
+ const last = result[result.length - 1];
28
+ if (last !== void 0 && last.role === "user") {
29
+ if (typeof last.content === "string") {
30
+ last.content = [
31
+ { type: "text", text: last.content },
32
+ toolResultBlock
33
+ ];
34
+ } else {
35
+ last.content.push(toolResultBlock);
36
+ }
37
+ } else {
38
+ result.push({ role: "user", content: [toolResultBlock] });
39
+ }
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+ function translateTools(tools) {
45
+ return tools.map((t) => ({
46
+ name: t.name,
47
+ description: t.description,
48
+ // as: harness Tool.inputSchema is Record<string,unknown>; SDK requires InputSchema with type:'object'
49
+ // which is always present at runtime — cannot be statically verified from the generic type
50
+ input_schema: t.inputSchema
51
+ }));
52
+ }
53
+ function mapStopReason(stopReason) {
54
+ if (stopReason === "end_turn") return "end";
55
+ if (stopReason === "tool_use") return "tool_use";
56
+ if (stopReason === "max_tokens") return "max_tokens";
57
+ return "end";
58
+ }
59
+ function normalizeResponse(response) {
60
+ let text = "";
61
+ const toolCalls = [];
62
+ for (const block of response.content) {
63
+ if (block.type === "text") {
64
+ text += block.text;
65
+ } else if (block.type === "tool_use") {
66
+ toolCalls.push({ id: block.id, name: block.name, input: block.input });
67
+ }
68
+ }
69
+ return {
70
+ text,
71
+ toolCalls,
72
+ stopReason: mapStopReason(response.stop_reason ?? "")
73
+ };
74
+ }
75
+ var ZEROED_STEP_CONTEXT = { agentId: "", sessionId: "", stepName: "" };
76
+ var Claude = class {
77
+ client;
78
+ model;
79
+ observer = {};
80
+ stepContext = ZEROED_STEP_CONTEXT;
81
+ /**
82
+ * @param model - Anthropic model ID, e.g. `'claude-3-5-haiku-20241022'`.
83
+ * @param options - Optional API key override.
84
+ */
85
+ constructor(model, options) {
86
+ this.model = model;
87
+ this.client = new Anthropic({ apiKey: options?.apiKey });
88
+ }
89
+ bindObserver(observer) {
90
+ this.observer = observer;
91
+ }
92
+ setStepContext(ctx) {
93
+ this.stepContext = ctx;
94
+ }
95
+ async invoke(messages, options) {
96
+ const translatedMessages = translateMessages(messages);
97
+ const tools = options?.tools;
98
+ const response = await this.client.messages.create({
99
+ model: this.model,
100
+ messages: translatedMessages,
101
+ max_tokens: 4096,
102
+ ...tools !== void 0 ? { tools: translateTools(tools) } : {}
103
+ });
104
+ const result = normalizeResponse(response);
105
+ const event = {
106
+ tokens: { input: response.usage.input_tokens, output: response.usage.output_tokens },
107
+ modelId: this.model,
108
+ stopReason: result.stopReason,
109
+ providerName: "anthropic"
110
+ };
111
+ this.observer.onEvent?.(this.stepContext, "llm.response", event);
112
+ return result;
113
+ }
114
+ };
115
+
116
+ // src/mock-claude.ts
117
+ var MockClaudeEmptyQueueError = class extends Error {
118
+ constructor() {
119
+ super("MockClaude has no responses configured \u2014 call new MockClaude(response) or enqueue(response) before invoke");
120
+ this.name = "MockClaudeEmptyQueueError";
121
+ }
122
+ };
123
+ var ZEROED_STEP_CONTEXT2 = { agentId: "", sessionId: "", stepName: "" };
124
+ var MockClaude = class {
125
+ /** The message list from the most recent `invoke()` call. */
126
+ lastMessages = [];
127
+ queue = [];
128
+ observer = {};
129
+ stepContext = ZEROED_STEP_CONTEXT2;
130
+ /**
131
+ * @param responses - One or more responses to queue up front. May also be
132
+ * added later via {@link enqueue}.
133
+ */
134
+ constructor(responses) {
135
+ if (responses !== void 0) {
136
+ this.enqueue(responses);
137
+ }
138
+ }
139
+ /** Add one or more responses to the end of the queue. */
140
+ enqueue(response) {
141
+ const items = Array.isArray(response) ? response : [response];
142
+ this.queue.push(...items);
143
+ }
144
+ bindObserver(observer) {
145
+ this.observer = observer;
146
+ }
147
+ setStepContext(ctx) {
148
+ this.stepContext = ctx;
149
+ }
150
+ async invoke(messages, options) {
151
+ void options;
152
+ if (this.queue.length === 0) {
153
+ throw new MockClaudeEmptyQueueError();
154
+ }
155
+ const response = this.queue.length > 1 ? this.queue.shift() : this.queue[0];
156
+ this.lastMessages = messages;
157
+ const event = {
158
+ tokens: { input: 0, output: 0 },
159
+ modelId: "mock",
160
+ stopReason: response.stopReason,
161
+ providerName: "mock"
162
+ };
163
+ this.observer.onEvent?.(this.stepContext, "llm.response", event);
164
+ return response;
165
+ }
166
+ };
167
+ export {
168
+ Claude,
169
+ MockClaude,
170
+ MockClaudeEmptyQueueError
171
+ };
172
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/claude.ts","../src/mock-claude.ts"],"sourcesContent":["import type { LLM, Message, Tool, ToolCall, LLMResponse, LLMUsageEvent } from '@noetaris/harness-types'\nimport type { ObserverAware, Observer, StepContext } from '@noetaris/harness'\nimport Anthropic from '@anthropic-ai/sdk'\nimport type { Tool as AnthropicSDKTool } from '@anthropic-ai/sdk/resources/messages/messages.js'\n\n/** Options for {@link Claude}. */\nexport interface ClaudeOptions {\n /** Anthropic API key. Defaults to the `ANTHROPIC_API_KEY` environment variable. */\n apiKey?: string\n}\n\ntype AnthropicContentBlock =\n | { type: 'text'; text: string }\n | { type: 'tool_use'; id: string; name: string; input: unknown }\n | { type: 'tool_result'; tool_use_id: string; content: string }\n\ntype AnthropicMessage = {\n role: 'user' | 'assistant'\n content: string | AnthropicContentBlock[]\n}\n\n// Use SDK's Tool type for the translated tools array passed to client.messages.create\ntype AnthropicTool = AnthropicSDKTool\n\nfunction translateMessages(messages: Message[]): AnthropicMessage[] {\n const result: AnthropicMessage[] = []\n\n for (const msg of messages) {\n if (msg.role === 'user') {\n result.push({ role: 'user', content: msg.content })\n } else if (msg.role === 'assistant') {\n if (msg.toolCalls && msg.toolCalls.length > 0) {\n const blocks: AnthropicContentBlock[] = []\n if (msg.content) {\n blocks.push({ type: 'text', text: msg.content })\n }\n for (const tc of msg.toolCalls) {\n blocks.push({ type: 'tool_use', id: tc.id, name: tc.name, input: tc.input })\n }\n result.push({ role: 'assistant', content: blocks })\n } else {\n result.push({ role: 'assistant', content: msg.content ?? '' })\n }\n } else if (msg.role === 'tool') {\n const toolResultBlock: AnthropicContentBlock = {\n type: 'tool_result',\n tool_use_id: msg.toolCallId,\n content: msg.content,\n }\n\n const last = result[result.length - 1]\n if (last !== undefined && last.role === 'user') {\n // last message is a user message — merge into it\n if (typeof last.content === 'string') {\n // convert string content to array with text block + tool_result\n last.content = [\n { type: 'text', text: last.content },\n toolResultBlock,\n ]\n } else {\n last.content.push(toolResultBlock)\n }\n } else {\n // no preceding user message — wrap in a new user turn\n result.push({ role: 'user', content: [toolResultBlock] })\n }\n }\n }\n\n return result\n}\n\nfunction translateTools(tools: Tool[]): AnthropicTool[] {\n return tools.map((t) => ({\n name: t.name,\n description: t.description,\n // as: harness Tool.inputSchema is Record<string,unknown>; SDK requires InputSchema with type:'object'\n // which is always present at runtime — cannot be statically verified from the generic type\n input_schema: t.inputSchema as AnthropicSDKTool['input_schema'],\n }))\n}\n\nfunction mapStopReason(stopReason: string): LLMResponse['stopReason'] {\n if (stopReason === 'end_turn') return 'end'\n if (stopReason === 'tool_use') return 'tool_use'\n if (stopReason === 'max_tokens') return 'max_tokens'\n return 'end'\n}\n\nfunction normalizeResponse(response: Anthropic.Message): LLMResponse {\n let text = ''\n const toolCalls: ToolCall[] = []\n\n for (const block of response.content) {\n if (block.type === 'text') {\n text += block.text\n } else if (block.type === 'tool_use') {\n toolCalls.push({ id: block.id, name: block.name, input: block.input })\n }\n }\n\n return {\n text,\n toolCalls,\n stopReason: mapStopReason(response.stop_reason ?? ''),\n }\n}\n\nconst ZEROED_STEP_CONTEXT: StepContext = { agentId: '', sessionId: '', stepName: '' }\n\n/**\n * {@link LLM} adapter for the Anthropic Messages API.\n *\n * Implements {@link ObserverAware} — when an observer is bound the adapter\n * emits an `'llm.response'` event carrying an `LLMUsageEvent` payload after\n * each successful invocation.\n *\n * @example\n * ```ts\n * const llm = new Claude('claude-3-5-haiku-20241022')\n * const response = await llm.invoke(messages)\n * ```\n */\nexport class Claude implements LLM, ObserverAware {\n private readonly client: Anthropic\n private readonly model: string\n private observer: Observer = {}\n private stepContext: StepContext = ZEROED_STEP_CONTEXT\n\n /**\n * @param model - Anthropic model ID, e.g. `'claude-3-5-haiku-20241022'`.\n * @param options - Optional API key override.\n */\n constructor(model: string, options?: ClaudeOptions) {\n this.model = model\n this.client = new Anthropic({ apiKey: options?.apiKey })\n }\n\n bindObserver(observer: Observer): void {\n this.observer = observer\n }\n\n setStepContext(ctx: StepContext): void {\n this.stepContext = ctx\n }\n\n async invoke(messages: Message[], options?: { tools?: Tool[] }): Promise<LLMResponse> {\n const translatedMessages = translateMessages(messages)\n const tools = options?.tools\n\n const response = await this.client.messages.create({\n model: this.model,\n messages: translatedMessages,\n max_tokens: 4096,\n ...(tools !== undefined ? { tools: translateTools(tools) } : {}),\n })\n\n const result = normalizeResponse(response)\n\n const event: LLMUsageEvent = {\n tokens: { input: response.usage.input_tokens, output: response.usage.output_tokens },\n modelId: this.model,\n stopReason: result.stopReason,\n providerName: 'anthropic',\n }\n this.observer.onEvent?.(this.stepContext, 'llm.response', event)\n\n return result\n }\n}\n","import type { LLM, Message, Tool, LLMResponse, LLMUsageEvent } from '@noetaris/harness-types'\nimport type { ObserverAware, Observer, StepContext } from '@noetaris/harness'\n\n/** Thrown by {@link MockClaude} when `invoke` is called with no responses queued. */\nexport class MockClaudeEmptyQueueError extends Error {\n constructor() {\n super('MockClaude has no responses configured — call new MockClaude(response) or enqueue(response) before invoke')\n this.name = 'MockClaudeEmptyQueueError'\n }\n}\n\nconst ZEROED_STEP_CONTEXT: StepContext = { agentId: '', sessionId: '', stepName: '' }\n\n/**\n * In-memory test double for {@link Claude}.\n *\n * Pre-load one or more {@link LLMResponse} objects; each `invoke()` call\n * dequeues the next response. The last response is **sticky** — once only\n * one remains it repeats indefinitely rather than throwing.\n *\n * `lastMessages` is populated after each `invoke()` call, allowing assertions\n * on the conversation history passed to the adapter.\n *\n * @example\n * ```ts\n * const llm = new MockClaude({ text: 'hello', toolCalls: [], stopReason: 'end' })\n * ```\n */\nexport class MockClaude implements LLM, ObserverAware {\n /** The message list from the most recent `invoke()` call. */\n lastMessages: Message[] = []\n\n private queue: LLMResponse[] = []\n private observer: Observer = {}\n private stepContext: StepContext = ZEROED_STEP_CONTEXT\n\n /**\n * @param responses - One or more responses to queue up front. May also be\n * added later via {@link enqueue}.\n */\n constructor(responses?: LLMResponse | LLMResponse[]) {\n if (responses !== undefined) {\n this.enqueue(responses)\n }\n }\n\n /** Add one or more responses to the end of the queue. */\n enqueue(response: LLMResponse | LLMResponse[]): void {\n const items = Array.isArray(response) ? response : [response]\n this.queue.push(...items)\n }\n\n bindObserver(observer: Observer): void {\n this.observer = observer\n }\n\n setStepContext(ctx: StepContext): void {\n this.stepContext = ctx\n }\n\n async invoke(messages: Message[], options?: { tools?: Tool[] }): Promise<LLMResponse> {\n void options\n if (this.queue.length === 0) {\n throw new MockClaudeEmptyQueueError()\n }\n\n // sticky-last: dequeue only when more than one element remains\n const response: LLMResponse = this.queue.length > 1\n ? (this.queue.shift() as LLMResponse) // as: shift() on non-empty array is always defined; length > 1 is checked above\n : (this.queue[0] as LLMResponse) // as: queue.length === 1 guaranteed by the empty check; index 0 is always defined\n\n this.lastMessages = messages\n\n const event: LLMUsageEvent = {\n tokens: { input: 0, output: 0 },\n modelId: 'mock',\n stopReason: response.stopReason,\n providerName: 'mock',\n }\n this.observer.onEvent?.(this.stepContext, 'llm.response', event)\n\n return response\n }\n}\n"],"mappings":"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","names":["ZEROED_STEP_CONTEXT"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@noetaris/harness-anthropic",
3
+ "version": "0.1.0",
4
+ "description": "Anthropic Claude adapter for @noetaris/harness",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/noetaris-lab/harness-anthropic.git"
9
+ },
10
+ "homepage": "https://github.com/noetaris-lab/harness-anthropic#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/noetaris-lab/harness-anthropic/issues"
13
+ },
14
+ "main": "./dist/index.js",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.js",
19
+ "types": "./dist/index.d.ts"
20
+ }
21
+ },
22
+ "engines": {
23
+ "node": ">=22"
24
+ },
25
+ "scripts": {
26
+ "build": "tsup",
27
+ "typecheck": "tsc --noEmit",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "prepublishOnly": "pnpm build && pnpm test",
31
+ "publish:npm": "pnpm publish --access public --no-git-checks"
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "pnpm": {
37
+ "onlyBuiltDependencies": [
38
+ "esbuild"
39
+ ]
40
+ },
41
+ "peerDependencies": {
42
+ "@noetaris/harness": ">=0.1.0",
43
+ "@noetaris/harness-types": ">=0.1.0"
44
+ },
45
+ "devDependencies": {
46
+ "@noetaris/harness": "^0.3.0",
47
+ "@noetaris/harness-types": "^0.2.0",
48
+ "@types/node": "^25.8.0",
49
+ "tsup": "^8.5.1",
50
+ "typescript": "^6.0.3",
51
+ "vitest": "^4.1.6"
52
+ },
53
+ "dependencies": {
54
+ "@anthropic-ai/sdk": "^0.96.0"
55
+ }
56
+ }