zidane 1.8.0 → 2.0.1

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.
Files changed (36) hide show
  1. package/dist/{agent-CWQ5XOw6.d.ts → agent-D-ZFMbSd.d.ts} +371 -21
  2. package/dist/{chunk-FFFDQHMA.js → chunk-7JTBBZ2U.js} +21 -0
  3. package/dist/chunk-BCXXXJ3G.js +779 -0
  4. package/dist/{chunk-WQBKOZVI.js → chunk-FRNFVKWW.js} +50 -12
  5. package/dist/{chunk-EC7IRWVS.js → chunk-LN4LLLHA.js} +101 -7
  6. package/dist/chunk-LVC7NQUZ.js +22 -0
  7. package/dist/chunk-MYWDHD7C.js +14 -0
  8. package/dist/{chunk-3RJOWJOJ.js → chunk-OVQ4N64O.js} +1 -1
  9. package/dist/{chunk-4N5ADW7A.js → chunk-PASFWG7S.js} +343 -32
  10. package/dist/{chunk-TBC6MSVK.js → chunk-PJUUYBKF.js} +53 -4
  11. package/dist/{chunk-2IB4XBQE.js → chunk-VG2E6YK3.js} +0 -97
  12. package/dist/harnesses.d.ts +1 -2
  13. package/dist/harnesses.js +5 -5
  14. package/dist/index.d.ts +5 -6
  15. package/dist/index.js +42 -12
  16. package/dist/mcp.d.ts +1 -2
  17. package/dist/mcp.js +3 -1
  18. package/dist/providers.d.ts +1 -2
  19. package/dist/providers.js +3 -3
  20. package/dist/session/sqlite.d.ts +16 -0
  21. package/dist/session/sqlite.js +98 -0
  22. package/dist/session.d.ts +1 -2
  23. package/dist/session.js +3 -5
  24. package/dist/skills-use-C4KFVla0.d.ts +66 -0
  25. package/dist/skills.d.ts +215 -30
  26. package/dist/skills.js +21 -2
  27. package/dist/{spawn-EEv1Johs.d.ts → spawn-RoqpjYLZ.d.ts} +1 -1
  28. package/dist/tools.d.ts +3 -4
  29. package/dist/tools.js +10 -4
  30. package/dist/types.d.ts +2 -3
  31. package/dist/types.js +8 -2
  32. package/package.json +12 -3
  33. package/dist/chunk-4C6Y56CC.js +0 -390
  34. package/dist/chunk-CFLC2I7D.js +0 -8
  35. package/dist/glob-j9gbk6xm.d.ts +0 -5
  36. package/dist/types-CDI8Kmve.d.ts +0 -64
@@ -5,15 +5,14 @@ import {
5
5
  toAnthropic,
6
6
  toolResultsMessage,
7
7
  userMessage
8
- } from "./chunk-EC7IRWVS.js";
8
+ } from "./chunk-LN4LLLHA.js";
9
9
  import {
10
10
  matchesContextExceeded
11
- } from "./chunk-FFFDQHMA.js";
11
+ } from "./chunk-7JTBBZ2U.js";
12
12
 
13
13
  // src/providers/anthropic.ts
14
14
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
15
15
  import { resolve as resolve2 } from "path";
16
- import Anthropic from "@anthropic-ai/sdk";
17
16
 
18
17
  // src/providers/oauth.ts
19
18
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -88,6 +87,21 @@ async function resolveOAuthApiKey(options, callbacks) {
88
87
 
89
88
  // src/providers/anthropic.ts
90
89
  var CREDENTIALS_FILE2 = resolve2(process.cwd(), ".credentials.json");
90
+ var _sdkCtor = null;
91
+ async function loadAnthropicSdk() {
92
+ if (_sdkCtor)
93
+ return _sdkCtor;
94
+ try {
95
+ const mod = await import("@anthropic-ai/sdk");
96
+ _sdkCtor = mod.default;
97
+ return _sdkCtor;
98
+ } catch (err) {
99
+ throw new Error(
100
+ "The `anthropic` provider requires the `@anthropic-ai/sdk` package, which is an optional peer dependency. Install it with your package manager (e.g. `bun add @anthropic-ai/sdk`).",
101
+ err instanceof Error ? { cause: err } : void 0
102
+ );
103
+ }
104
+ }
91
105
  function getConfiguredApiKey(anthropicParams) {
92
106
  if (anthropicParams?.apiKey)
93
107
  return anthropicParams.apiKey;
@@ -102,9 +116,9 @@ function getConfiguredApiKey(anthropicParams) {
102
116
  }
103
117
  throw new Error("No API key found. Run `bun run auth` first.");
104
118
  }
105
- function createClient(apiKey, isOAuth, baseURL) {
119
+ function createClient(SDK, apiKey, isOAuth, baseURL) {
106
120
  const base = baseURL ? { baseURL } : {};
107
- return new Anthropic(
121
+ return new SDK(
108
122
  isOAuth ? {
109
123
  apiKey: null,
110
124
  authToken: apiKey,
@@ -144,13 +158,19 @@ function mapStopReason(stopReason) {
144
158
  return "other";
145
159
  }
146
160
  }
161
+ function looksLikeAnthropicApiError(err) {
162
+ if (!err || typeof err !== "object")
163
+ return false;
164
+ const e = err;
165
+ return typeof e.status === "number" && "error" in e;
166
+ }
147
167
  function classifyAnthropicError(err) {
148
168
  if (!err || typeof err !== "object")
149
169
  return null;
150
170
  const anyErr = err;
151
171
  if (anyErr.name === "AbortError")
152
172
  return { kind: "aborted" };
153
- if (!(err instanceof Anthropic.APIError))
173
+ if (!looksLikeAnthropicApiError(err))
154
174
  return null;
155
175
  const innerType = anyErr.error?.error?.type;
156
176
  const outerType = anyErr.error?.type;
@@ -206,7 +226,14 @@ function anthropic(anthropicParams) {
206
226
  } : void 0;
207
227
  return {
208
228
  name: "anthropic",
209
- meta: { defaultModel, isOAuth },
229
+ meta: {
230
+ defaultModel,
231
+ isOAuth,
232
+ capabilities: {
233
+ vision: true,
234
+ imageInToolResult: true
235
+ }
236
+ },
210
237
  formatTools(tools) {
211
238
  return tools.map((t) => ({
212
239
  name: t.name,
@@ -246,6 +273,7 @@ function anthropic(anthropicParams) {
246
273
  promptMessage: anthropicPromptMessage,
247
274
  classifyError: classifyAnthropicError,
248
275
  async stream(options, callbacks) {
276
+ const SDK = await loadAnthropicSdk();
249
277
  const apiKey = await resolveOAuthApiKey(
250
278
  {
251
279
  provider: "anthropic",
@@ -269,7 +297,7 @@ function anthropic(anthropicParams) {
269
297
  }
270
298
  }
271
299
  );
272
- const client = createClient(apiKey, apiKey.includes("sk-ant-oat"), anthropicParams?.baseURL);
300
+ const client = createClient(SDK, apiKey, apiKey.includes("sk-ant-oat"), anthropicParams?.baseURL);
273
301
  const system = isOAuth ? `You are Claude Code, Anthropic's official CLI for Claude.` : options.system;
274
302
  const messages = isOAuth && options.system ? [
275
303
  { role: "user", content: [{ type: "text", text: options.system }] },
@@ -352,7 +380,8 @@ function cerebras(params) {
352
380
  name: "cerebras",
353
381
  apiKey,
354
382
  baseURL: BASE_URL,
355
- defaultModel: params?.defaultModel || "zai-glm-4.7"
383
+ defaultModel: params?.defaultModel || "zai-glm-4.7",
384
+ capabilities: params?.capabilities ?? { vision: false, imageInToolResult: false }
356
385
  });
357
386
  }
358
387
 
@@ -393,11 +422,12 @@ function toPiMessages(messages, modelId) {
393
422
  const toolResults = msg.content.filter((b) => b.type === "tool_result");
394
423
  if (toolResults.length > 0) {
395
424
  for (const result of toolResults) {
425
+ const content2 = typeof result.output === "string" ? [{ type: "text", text: result.output }] : result.output.map((block) => block.type === "image" ? { type: "image", data: block.data, mimeType: block.mediaType } : { type: "text", text: block.text });
396
426
  out.push({
397
427
  role: "toolResult",
398
428
  toolCallId: result.callId,
399
429
  toolName: "",
400
- content: [{ type: "text", text: result.output }],
430
+ content: content2,
401
431
  isError: result.isError ?? false,
402
432
  timestamp: Date.now()
403
433
  });
@@ -524,7 +554,14 @@ function openai(params) {
524
554
  } : void 0;
525
555
  return {
526
556
  name: "openai",
527
- meta: { defaultModel, isOAuth: true },
557
+ meta: {
558
+ defaultModel,
559
+ isOAuth: true,
560
+ capabilities: {
561
+ vision: true,
562
+ imageInToolResult: true
563
+ }
564
+ },
528
565
  formatTools,
529
566
  userMessage,
530
567
  assistantMessage,
@@ -629,7 +666,8 @@ function openrouter(params) {
629
666
  extraHeaders: {
630
667
  "HTTP-Referer": "https://github.com/Tahul/zidane",
631
668
  "X-Title": "zidane"
632
- }
669
+ },
670
+ capabilities: params?.capabilities ?? { vision: true, imageInToolResult: false }
633
671
  });
634
672
  }
635
673
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  matchesContextExceeded
3
- } from "./chunk-FFFDQHMA.js";
3
+ } from "./chunk-7JTBBZ2U.js";
4
4
 
5
5
  // src/providers/openai-compat.ts
6
6
  var TOOL_RESULTS_TAG = "__zidane_tool_results__";
@@ -84,8 +84,28 @@ async function consumeSSE(response, callbacks, signal) {
84
84
  }));
85
85
  return { text, thinking, toolCalls, finishReason, usage };
86
86
  }
87
- function toOAIMessages(system, messages) {
87
+ function toImageUrlPart(img) {
88
+ return {
89
+ type: "image_url",
90
+ image_url: { url: `data:${img.mediaType};base64,${img.data}` }
91
+ };
92
+ }
93
+ function summarizeToolResultOutput(output) {
94
+ if (typeof output === "string")
95
+ return { text: output, images: [] };
96
+ const texts = [];
97
+ const images = [];
98
+ for (const block of output) {
99
+ if (block.type === "text")
100
+ texts.push(block.text);
101
+ else if (block.type === "image")
102
+ images.push({ mediaType: block.mediaType, data: block.data });
103
+ }
104
+ return { text: texts.join("\n"), images };
105
+ }
106
+ function toOAIMessages(system, messages, options = {}) {
88
107
  const out = [{ role: "system", content: system }];
108
+ const nativeImageInTool = options.imageInToolResult === true;
89
109
  for (const msg of messages) {
90
110
  const toolResults = msg.content.filter((b) => b.type === "tool_result");
91
111
  const toolCalls = msg.content.filter((b) => b.type === "tool_call");
@@ -93,7 +113,33 @@ function toOAIMessages(system, messages) {
93
113
  const imageBlocks = msg.content.filter((b) => b.type === "image");
94
114
  if (toolResults.length > 0) {
95
115
  for (const tr of toolResults) {
96
- out.push({ role: "tool", tool_call_id: tr.callId, content: tr.output });
116
+ if (typeof tr.output === "string") {
117
+ out.push({ role: "tool", tool_call_id: tr.callId, content: tr.output });
118
+ continue;
119
+ }
120
+ if (nativeImageInTool) {
121
+ const parts = tr.output.map((block) => block.type === "image" ? toImageUrlPart({ mediaType: block.mediaType, data: block.data }) : { type: "text", text: block.text });
122
+ out.push({ role: "tool", tool_call_id: tr.callId, content: parts });
123
+ continue;
124
+ }
125
+ const { text, images } = summarizeToolResultOutput(tr.output);
126
+ if (images.length === 0) {
127
+ out.push({ role: "tool", tool_call_id: tr.callId, content: text });
128
+ continue;
129
+ }
130
+ const noun = images.length === 1 ? "image" : "images";
131
+ const attachedMarker = `[${images.length} ${noun} attached \u2014 see next user message]`;
132
+ const toolMarker = text.length > 0 ? `${text}
133
+
134
+ ${attachedMarker}` : attachedMarker;
135
+ out.push({ role: "tool", tool_call_id: tr.callId, content: toolMarker });
136
+ out.push({
137
+ role: "user",
138
+ content: [
139
+ ...images.map(toImageUrlPart),
140
+ { type: "text", text: `(${noun} returned by tool call ${tr.callId})` }
141
+ ]
142
+ });
97
143
  }
98
144
  continue;
99
145
  }
@@ -244,9 +290,13 @@ function openaiCompat(params) {
244
290
  const authHeaderValue = params.authHeader?.scheme ? `${params.authHeader.scheme} ${params.apiKey}` : params.authHeader ? params.apiKey : `Bearer ${params.apiKey}`;
245
291
  const extraHeaders = params.extraHeaders ?? {};
246
292
  const endpoint = `${params.baseURL.replace(TRAILING_SLASH_RE, "")}/chat/completions`;
293
+ const capabilities = {
294
+ vision: params.capabilities?.vision ?? false,
295
+ imageInToolResult: params.capabilities?.imageInToolResult ?? false
296
+ };
247
297
  return {
248
298
  name,
249
- meta: { defaultModel },
299
+ meta: { defaultModel, capabilities },
250
300
  formatTools,
251
301
  userMessage,
252
302
  assistantMessage,
@@ -254,7 +304,9 @@ function openaiCompat(params) {
254
304
  classifyError: classifyOpenAICompatError,
255
305
  async stream(options, callbacks) {
256
306
  const modelId = options.model || defaultModel;
257
- const messages = toOAIMessages(options.system, options.messages);
307
+ const messages = toOAIMessages(options.system, options.messages, {
308
+ imageInToolResult: capabilities.imageInToolResult === true
309
+ });
258
310
  const maxTokens = options.thinkingBudget ? options.thinkingBudget + options.maxTokens : options.maxTokens;
259
311
  const body = {
260
312
  model: modelId,
@@ -306,6 +358,48 @@ function openaiCompat(params) {
306
358
  }
307
359
 
308
360
  // src/session/messages.ts
361
+ function decodeAnthropicToolResultContent(content) {
362
+ if (typeof content === "string")
363
+ return content;
364
+ if (!Array.isArray(content))
365
+ return JSON.stringify(content);
366
+ const blocks = [];
367
+ for (const raw of content) {
368
+ if (!raw || typeof raw !== "object")
369
+ continue;
370
+ const b = raw;
371
+ if (b.type === "text" && typeof b.text === "string") {
372
+ blocks.push({ type: "text", text: b.text });
373
+ continue;
374
+ }
375
+ if (b.type === "image" && b.source && typeof b.source === "object") {
376
+ const src = b.source;
377
+ if (src.type === "base64" && typeof src.data === "string" && typeof src.media_type === "string") {
378
+ blocks.push({ type: "image", mediaType: src.media_type, data: src.data });
379
+ continue;
380
+ }
381
+ }
382
+ blocks.push({ type: "text", text: JSON.stringify(raw) });
383
+ }
384
+ if (blocks.length === 0)
385
+ return "";
386
+ const hasNonText = blocks.some((b) => b.type !== "text");
387
+ if (!hasNonText)
388
+ return blocks.map((b) => b.text).join("\n");
389
+ return blocks;
390
+ }
391
+ function encodeAnthropicToolResultContent(output) {
392
+ if (typeof output === "string")
393
+ return output;
394
+ return output.map((b) => {
395
+ if (b.type === "text")
396
+ return { type: "text", text: b.text };
397
+ return {
398
+ type: "image",
399
+ source: { type: "base64", media_type: b.mediaType, data: b.data }
400
+ };
401
+ });
402
+ }
309
403
  function fromAnthropic(msg) {
310
404
  const role = msg.role;
311
405
  const content = [];
@@ -328,7 +422,7 @@ function fromAnthropic(msg) {
328
422
  } else if (b.type === "tool_use") {
329
423
  content.push({ type: "tool_call", id: b.id, name: b.name, input: b.input });
330
424
  } else if (b.type === "tool_result") {
331
- const output = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
425
+ const output = decodeAnthropicToolResultContent(b.content);
332
426
  content.push({ type: "tool_result", callId: b.tool_use_id, output });
333
427
  } else if (b.type === "thinking") {
334
428
  content.push({ type: "thinking", text: b.thinking, signature: b.signature });
@@ -398,7 +492,7 @@ function toAnthropic(msg) {
398
492
  case "tool_call":
399
493
  return { type: "tool_use", id: block.id, name: block.name, input: block.input };
400
494
  case "tool_result":
401
- return { type: "tool_result", tool_use_id: block.callId, content: block.output };
495
+ return { type: "tool_result", tool_use_id: block.callId, content: encodeAnthropicToolResultContent(block.output) };
402
496
  case "thinking":
403
497
  return { type: "thinking", thinking: block.text, signature: block.signature };
404
498
  default:
@@ -0,0 +1,22 @@
1
+ import {
2
+ validateSkillForWrite
3
+ } from "./chunk-BCXXXJ3G.js";
4
+
5
+ // src/skills/index.ts
6
+ function defineSkill(config) {
7
+ const normalized = {
8
+ ...config,
9
+ source: config.source ?? "inline"
10
+ };
11
+ const result = validateSkillForWrite(normalized);
12
+ if (!result.valid) {
13
+ const summary = result.errors.map((e) => ` - [${e.code}] ${e.message}`).join("\n");
14
+ throw new Error(`Invalid skill "${normalized.name}":
15
+ ${summary}`);
16
+ }
17
+ return normalized;
18
+ }
19
+
20
+ export {
21
+ defineSkill
22
+ };
@@ -0,0 +1,14 @@
1
+ // src/types.ts
2
+ function toolResultToText(content) {
3
+ if (typeof content === "string")
4
+ return content;
5
+ return content.map((block) => {
6
+ if (block.type === "text")
7
+ return block.text;
8
+ return `[image: ${block.mediaType} \u2014 ${block.data.length} b64 bytes]`;
9
+ }).join("\n");
10
+ }
11
+
12
+ export {
13
+ toolResultToText
14
+ };
@@ -4,7 +4,7 @@ import {
4
4
  shell,
5
5
  spawn,
6
6
  writeFile
7
- } from "./chunk-4N5ADW7A.js";
7
+ } from "./chunk-PASFWG7S.js";
8
8
 
9
9
  // src/harnesses/basic.ts
10
10
  var basicTools = { shell, readFile, writeFile, listFiles };