@automatalabs/acp-agents 0.20.2 → 0.20.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/backends/claude.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAM5E,qBAAa,aAAc,YAAW,OAAO;IAC3C,QAAQ,CAAC,EAAE,EAAG,QAAQ,CAAU;IAEhC,WAAW,IAAI,WAAW;IAgB1B,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAe7E,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAKjD,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO;CAGpD"}
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/backends/claude.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAM5E,qBAAa,aAAc,YAAW,OAAO;IAC3C,QAAQ,CAAC,EAAE,EAAG,QAAQ,CAAU;IAEhC,WAAW,IAAI,WAAW;IAgB1B,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAmB7E,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAKjD,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO;CAGpD"}
@@ -6,7 +6,7 @@
6
6
  // `_claude/sdkMessage` extension notification (the runner's ACP client captures it).
7
7
  import { createRequire } from "node:module";
8
8
  import { splitArgs } from "../backend.js";
9
- import { toJsonSchema } from "../schema-strict.js";
9
+ import { toAnthropicJsonSchema } from "../schema-strict.js";
10
10
  const require = createRequire(import.meta.url);
11
11
  export class ClaudeBackend {
12
12
  id = "claude";
@@ -31,10 +31,14 @@ export class ClaudeBackend {
31
31
  // optional SessionMetaInputs (the seam still accepts them via the Backend interface).
32
32
  if (!schema)
33
33
  return undefined;
34
+ // Anthropic structured outputs accept only a JSON-Schema subset (additionalProperties:false
35
+ // required on every object; numeric/string/array constraints rejected). Normalize the wire
36
+ // copy so the native constraint always engages — an incompatible schema would fail the SDK
37
+ // constraint and silently degrade the run to unconstrained text + the repair ladder.
34
38
  const meta = {
35
39
  claudeCode: {
36
40
  options: {
37
- outputFormat: { type: "json_schema", schema: toJsonSchema(schema) },
41
+ outputFormat: { type: "json_schema", schema: toAnthropicJsonSchema(schema) },
38
42
  },
39
43
  emitRawSDKMessages: true,
40
44
  },
package/dist/index.d.ts CHANGED
@@ -27,7 +27,7 @@ export { decidePermission } from "./permissions.js";
27
27
  export type { ElicitationResolver, PermissionResolver, ToolPolicy } from "./permissions.js";
28
28
  export { UsageAccumulator } from "./usage.js";
29
29
  export type { McpAcpServerConfig, McpServerConfig } from "@automatalabs/shared-types";
30
- export { toJsonSchema, toStrictJsonSchema } from "./schema-strict.js";
30
+ export { toAnthropicJsonSchema, toJsonSchema, toStrictJsonSchema } from "./schema-strict.js";
31
31
  export { extractValidated, findJsonBlock, parseFinalJson, resolveStructuredOutput, validateValue, } from "./structured-output.js";
32
32
  export type { ResolveOptions, StructuredSession } from "./structured-output.js";
33
33
  export { ACP_AUTH_REQUIRED_ERROR_CODE, errorText, mapThrownError } from "./errors-map.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -26,6 +26,6 @@ export { OpenCodeBackend } from "./backends/opencode.js";
26
26
  export { CustomAcpBackend } from "./backends/custom.js";
27
27
  export { decidePermission } from "./permissions.js";
28
28
  export { UsageAccumulator } from "./usage.js";
29
- export { toJsonSchema, toStrictJsonSchema } from "./schema-strict.js";
29
+ export { toAnthropicJsonSchema, toJsonSchema, toStrictJsonSchema } from "./schema-strict.js";
30
30
  export { extractValidated, findJsonBlock, parseFinalJson, resolveStructuredOutput, validateValue, } from "./structured-output.js";
31
31
  export { ACP_AUTH_REQUIRED_ERROR_CODE, errorText, mapThrownError } from "./errors-map.js";
@@ -1,6 +1,17 @@
1
1
  import type { TSchema } from "typebox";
2
- /** Deep-clone a typebox schema into a plain JSON Schema object (Claude `outputFormat.schema`). */
2
+ /** Deep-clone a typebox schema into a plain JSON Schema object (prompt embedding / MCP tool
3
+ * inputSchema — surfaces with no provider-side keyword restrictions). */
3
4
  export declare function toJsonSchema(schema: TSchema): Record<string, unknown>;
5
+ /**
6
+ * Deep-clone a typebox schema and normalize it to the subset Anthropic structured outputs
7
+ * accepts (Claude `outputFormat.schema`): additionalProperties:false on every object,
8
+ * unsupported validation keywords / formats / regex features stripped, oneOf -> anyOf.
9
+ * Authored `required` is preserved (optional properties stay optional). Without this, an
10
+ * Anthropic-incompatible schema makes the SDK's native constraint fail and the run silently
11
+ * degrades to unconstrained text + the repair ladder. Operates on the clone only — the schema
12
+ * that feeds hashAgentCall is never mutated.
13
+ */
14
+ export declare function toAnthropicJsonSchema(schema: TSchema): Record<string, unknown>;
4
15
  /**
5
16
  * Deep-clone a typebox schema and normalize it to OpenAI STRICT rules (Codex
6
17
  * `turn/start.outputSchema`): every property required, additionalProperties:false,
@@ -1 +1 @@
1
- {"version":3,"file":"schema-strict.d.ts","sourceRoot":"","sources":["../src/schema-strict.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErE;AA6LD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG3E"}
1
+ {"version":3,"file":"schema-strict.d.ts","sourceRoot":"","sources":["../src/schema-strict.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC;0EAC0E;AAC1E,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAErE;AAqHD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG9E;AAmMD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAG3E"}
@@ -1,7 +1,135 @@
1
- /** Deep-clone a typebox schema into a plain JSON Schema object (Claude `outputFormat.schema`). */
1
+ /** Deep-clone a typebox schema into a plain JSON Schema object (prompt embedding / MCP tool
2
+ * inputSchema — surfaces with no provider-side keyword restrictions). */
2
3
  export function toJsonSchema(schema) {
3
4
  return JSON.parse(JSON.stringify(schema));
4
5
  }
6
+ // JSON-Schema keywords Anthropic structured outputs REJECTS with a 400 (numeric/string/array
7
+ // constraints, composition/annotation keywords outside its supported subset). Stripped on the
8
+ // COPY sent as Claude's `outputFormat.schema`; the ORIGINAL schema still backs the client-side
9
+ // typebox validation, so a stripped constraint is enforced there instead of on the wire.
10
+ const ANTHROPIC_UNSUPPORTED_KEYWORDS = new Set([
11
+ "$schema",
12
+ "$id",
13
+ "title",
14
+ "examples",
15
+ "minLength",
16
+ "maxLength",
17
+ "minimum",
18
+ "maximum",
19
+ "exclusiveMinimum",
20
+ "exclusiveMaximum",
21
+ "multipleOf",
22
+ "maxItems",
23
+ "uniqueItems",
24
+ "contains",
25
+ "minContains",
26
+ "maxContains",
27
+ "minProperties",
28
+ "maxProperties",
29
+ "contentEncoding",
30
+ "contentMediaType",
31
+ "patternProperties",
32
+ "additionalItems",
33
+ "unevaluatedProperties",
34
+ "unevaluatedItems",
35
+ "dependencies",
36
+ "dependentRequired",
37
+ "dependentSchemas",
38
+ "propertyNames",
39
+ "if",
40
+ "then",
41
+ "else",
42
+ "not",
43
+ "readOnly",
44
+ "writeOnly",
45
+ "deprecated",
46
+ ]);
47
+ // The only `format` values Anthropic structured outputs accepts; any other value is a 400.
48
+ const ANTHROPIC_SUPPORTED_FORMATS = new Set([
49
+ "date-time",
50
+ "time",
51
+ "date",
52
+ "duration",
53
+ "email",
54
+ "hostname",
55
+ "uri",
56
+ "ipv4",
57
+ "ipv6",
58
+ "uuid",
59
+ ]);
60
+ // Regex features Anthropic's `pattern` support excludes: backreferences, lookaround, word
61
+ // boundaries. A pattern using any of these is dropped from the wire copy (typebox still
62
+ // enforces it client-side) rather than risking a 400 that silently disables the constraint.
63
+ const ANTHROPIC_UNSUPPORTED_REGEX = /\\[1-9]|\(\?<?[=!]|\\[bB]/;
64
+ /** Keys whose value is a NAME -> subschema map: the names are data, not JSON-Schema keywords,
65
+ * so keyword filtering must not apply to them (a property literally named "format" survives). */
66
+ const SCHEMA_MAP_KEYS = new Set(["properties", "$defs", "definitions"]);
67
+ function normalizeSchemaMap(value, normalize) {
68
+ if (value === null || typeof value !== "object" || Array.isArray(value))
69
+ return value;
70
+ const out = {};
71
+ for (const [name, sub] of Object.entries(value)) {
72
+ out[name] = normalize(sub);
73
+ }
74
+ return out;
75
+ }
76
+ function normalizeAnthropicNode(node) {
77
+ if (Array.isArray(node))
78
+ return node.map(normalizeAnthropicNode);
79
+ if (node === null || typeof node !== "object")
80
+ return node;
81
+ const input = node;
82
+ const out = {};
83
+ for (const [key, value] of Object.entries(input)) {
84
+ if (SCHEMA_MAP_KEYS.has(key)) {
85
+ out[key] = normalizeSchemaMap(value, normalizeAnthropicNode);
86
+ continue;
87
+ }
88
+ if (ANTHROPIC_UNSUPPORTED_KEYWORDS.has(key))
89
+ continue;
90
+ if (key === "minItems") {
91
+ // Supported only for the values 0 and 1; anything larger is a 400.
92
+ if (value === 0 || value === 1)
93
+ out[key] = value;
94
+ continue;
95
+ }
96
+ if (key === "format") {
97
+ if (typeof value === "string" && ANTHROPIC_SUPPORTED_FORMATS.has(value))
98
+ out[key] = value;
99
+ continue;
100
+ }
101
+ if (key === "pattern") {
102
+ if (typeof value === "string" && !ANTHROPIC_UNSUPPORTED_REGEX.test(value))
103
+ out[key] = value;
104
+ continue;
105
+ }
106
+ // `oneOf` is not in Anthropic's supported subset; its branches are an exclusive subset of
107
+ // anyOf, so mapping over only widens acceptance — typebox re-narrows client-side.
108
+ const targetKey = key === "oneOf" ? "anyOf" : key;
109
+ out[targetKey] = normalizeAnthropicNode(value);
110
+ }
111
+ // Anthropic REQUIRES additionalProperties:false on EVERY object (true / a subschema / absent
112
+ // are all 400s). Unlike OpenAI strict, `required` is left as authored — Anthropic allows
113
+ // optional properties, so no all-required forcing and no null-widening here.
114
+ const properties = out["properties"];
115
+ const isObjectSchema = out["type"] === "object" || (out["type"] === undefined && properties !== undefined);
116
+ if (isObjectSchema)
117
+ out["additionalProperties"] = false;
118
+ return out;
119
+ }
120
+ /**
121
+ * Deep-clone a typebox schema and normalize it to the subset Anthropic structured outputs
122
+ * accepts (Claude `outputFormat.schema`): additionalProperties:false on every object,
123
+ * unsupported validation keywords / formats / regex features stripped, oneOf -> anyOf.
124
+ * Authored `required` is preserved (optional properties stay optional). Without this, an
125
+ * Anthropic-incompatible schema makes the SDK's native constraint fail and the run silently
126
+ * degrades to unconstrained text + the repair ladder. Operates on the clone only — the schema
127
+ * that feeds hashAgentCall is never mutated.
128
+ */
129
+ export function toAnthropicJsonSchema(schema) {
130
+ const clone = JSON.parse(JSON.stringify(schema));
131
+ return normalizeAnthropicNode(clone);
132
+ }
5
133
  // JSON-Schema keywords OpenAI strict structured output does NOT accept. Stripped on the
6
134
  // COPY before sending to Codex (turn/start.outputSchema is sent in strict mode). Structural
7
135
  // keywords (type/properties/items/enum/anyOf/oneOf/allOf/$ref/$defs/definitions/const/
@@ -57,6 +185,12 @@ function normalizeStrictNode(node) {
57
185
  }
58
186
  const out = {};
59
187
  for (const [key, value] of Object.entries(input)) {
188
+ if (SCHEMA_MAP_KEYS.has(key)) {
189
+ // name -> subschema maps: the names are data, never keyword-filtered (a property
190
+ // literally named "format" or "title" must survive).
191
+ out[key] = normalizeSchemaMap(value, normalizeStrictNode);
192
+ continue;
193
+ }
60
194
  if (STRICT_UNSUPPORTED_KEYWORDS.has(key))
61
195
  continue;
62
196
  // OpenAI strict accepts `anyOf` but not `oneOf` — map it over (its branches are an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automatalabs/acp-agents",
3
- "version": "0.20.2",
3
+ "version": "0.20.4",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -27,7 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@agentclientprotocol/claude-agent-acp": "0.56.0",
30
+ "@agentclientprotocol/claude-agent-acp": "0.57.0",
31
31
  "@agentclientprotocol/sdk": "^1.2.1",
32
32
  "@automatalabs/codex-acp": "1.4.0",
33
33
  "@modelcontextprotocol/sdk": "^1.29",