@2kw/ai 6.3.0-dev.12 → 6.3.0-dev.122

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 (53) hide show
  1. package/README.md +4 -1
  2. package/dist/agent-config/schema.d.ts +6 -3
  3. package/dist/agent-config/schema.js +15 -4
  4. package/dist/agent-config/template.js +1 -1
  5. package/dist/commands/agent-apply.js +1 -1
  6. package/dist/commands/agent-policy.d.ts +2 -1
  7. package/dist/commands/agent-policy.js +9 -2
  8. package/dist/commands/agent-run.d.ts +5 -0
  9. package/dist/commands/agent-run.js +47 -21
  10. package/dist/commands/agents.js +33 -6
  11. package/dist/commands/ai.js +3 -9
  12. package/dist/commands/auth.js +6 -1
  13. package/dist/commands/billing.js +5 -3
  14. package/dist/commands/config.d.ts +1 -1
  15. package/dist/commands/config.js +16 -2
  16. package/dist/commands/connectors.js +2 -1
  17. package/dist/commands/conversations.js +16 -0
  18. package/dist/commands/datasets.js +17 -15
  19. package/dist/commands/experiments.js +36 -26
  20. package/dist/commands/files.js +10 -28
  21. package/dist/commands/installations.js +46 -1
  22. package/dist/commands/knowledge-documents.js +24 -32
  23. package/dist/commands/knowledge.js +5 -0
  24. package/dist/commands/memory.d.ts +10 -0
  25. package/dist/commands/memory.js +132 -0
  26. package/dist/commands/prompts.js +9 -8
  27. package/dist/commands/schemas.js +15 -6
  28. package/dist/commands/settings.d.ts +13 -0
  29. package/dist/commands/settings.js +80 -0
  30. package/dist/commands/skill-versions.js +27 -1
  31. package/dist/commands/skills.js +31 -1
  32. package/dist/commands/tracing.js +12 -17
  33. package/dist/index.js +4 -0
  34. package/dist/lib/agent-decide.d.ts +29 -2
  35. package/dist/lib/agent-decide.js +100 -3
  36. package/dist/lib/agent-run.d.ts +50 -3
  37. package/dist/lib/agent-run.js +166 -16
  38. package/dist/lib/approval-prompt.js +31 -1
  39. package/dist/lib/client.d.ts +8 -0
  40. package/dist/lib/client.js +20 -1
  41. package/dist/lib/config.d.ts +16 -0
  42. package/dist/lib/config.js +26 -1
  43. package/dist/lib/connect-pause.d.ts +71 -0
  44. package/dist/lib/connect-pause.js +147 -0
  45. package/dist/lib/errors.d.ts +6 -0
  46. package/dist/lib/errors.js +8 -3
  47. package/dist/lib/overlay.d.ts +10 -0
  48. package/dist/lib/overlay.js +20 -0
  49. package/dist/lib/skills-apply-preview.d.ts +19 -0
  50. package/dist/lib/skills-apply-preview.js +94 -0
  51. package/dist/lib/tracing-settings.d.ts +26 -0
  52. package/dist/lib/tracing-settings.js +25 -0
  53. package/package.json +1 -1
@@ -10,12 +10,18 @@ export interface ApiErrorBody {
10
10
  timestamp: string;
11
11
  /** Machine-readable code from an OpenAI-style gateway error, e.g. `approval_hmac_mismatch`. */
12
12
  code?: string;
13
+ /**
14
+ * Machine-readable code from a problem detail's `errorCode`, e.g. `CONNECTOR_HOST_SIGN_IN_REQUIRED`.
15
+ * Kept apart from {@link code}: that one holds lowercase gateway codes and is printed by `--json`.
16
+ */
17
+ errorCode?: string;
13
18
  }
14
19
  export declare class BackboneApiError extends Error {
15
20
  readonly status: number;
16
21
  readonly errorType: string;
17
22
  readonly timestamp: string;
18
23
  readonly code?: string;
24
+ readonly errorCode?: string;
19
25
  constructor(body: Omit<ApiErrorBody, "error"> & {
20
26
  error: string;
21
27
  });
@@ -7,6 +7,7 @@ export class BackboneApiError extends Error {
7
7
  errorType;
8
8
  timestamp;
9
9
  code;
10
+ errorCode;
10
11
  constructor(body) {
11
12
  super(body.message);
12
13
  this.name = "BackboneApiError";
@@ -14,6 +15,7 @@ export class BackboneApiError extends Error {
14
15
  this.errorType = body.error;
15
16
  this.timestamp = body.timestamp;
16
17
  this.code = body.code;
18
+ this.errorCode = body.errorCode;
17
19
  }
18
20
  }
19
21
  /**
@@ -93,7 +95,9 @@ const PENDING_APPROVALS_HINT = "The approval was already decided or its response
93
95
  const CODE_HINTS = {
94
96
  approval_hmac_mismatch: PENDING_APPROVALS_HINT,
95
97
  unknown_approval_id: PENDING_APPROVALS_HINT,
96
- incomplete_tool_outputs: "Every pending approval of a paused response must be decided in one call. Use --approve-all or --reject-all, or name every id.",
98
+ incomplete_tool_outputs: "Every released tool call and every pending approval of a paused response must be answered in one call. " +
99
+ "Check pendingToolCalls and pendingApprovals in the run envelope.",
100
+ unknown_tool_output: "That call id was not released by this response. Use the responseId of the latest envelope.",
97
101
  conversation_agent_mismatch: "This conversation belongs to another agent. Start a new conversation or run the agent that owns it.",
98
102
  };
99
103
  /** The most specific hint for an API error: gateway code, then known messages, then the status table. */
@@ -108,8 +112,9 @@ export function hintFor(err) {
108
112
  return CODE_HINTS[err.code];
109
113
  // The 403 whose cause is the credential, not the role (#805). Without this the
110
114
  // generic 403 hint tells an organization admin to check a role that is already
111
- // right, and no role would ever have fixed it.
112
- if (err.status === 403 && /^Approved connector hosts are managed by a signed-in/.test(err.message)) {
115
+ // right, and no role would ever have fixed it. Matched on the backend's error code,
116
+ // so a reworded message cannot silently drop the hint.
117
+ if (err.errorCode === "CONNECTOR_HOST_SIGN_IN_REQUIRED") {
113
118
  return "Approved hosts need a browser sign-in: run 2kw auth login. An API key cannot manage them, whatever its role.";
114
119
  }
115
120
  // Anchored on the agent service's wording: prompts and schemas send the same
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The body for a PUT that replaces the whole row: the stored resource as its GET returned it, with
3
+ * every change the caller gave written over it. A change that is `undefined` was not given and keeps
4
+ * the stored value; the backend would store it as null otherwise (#1195). Server-managed fields in
5
+ * `current` (a dataset's or prompt's latestVersionId) go back as read, which is what keeps them.
6
+ */
7
+ export declare function overlay<T extends object>(current: T, changes: Record<string, unknown>): T;
8
+ /** Refuses a --name that is present but blank, which a full-replace PUT would otherwise store. */
9
+ export declare function assertNameNotBlank(name: string | undefined): void;
10
+ //# sourceMappingURL=overlay.d.ts.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The body for a PUT that replaces the whole row: the stored resource as its GET returned it, with
3
+ * every change the caller gave written over it. A change that is `undefined` was not given and keeps
4
+ * the stored value; the backend would store it as null otherwise (#1195). Server-managed fields in
5
+ * `current` (a dataset's or prompt's latestVersionId) go back as read, which is what keeps them.
6
+ */
7
+ export function overlay(current, changes) {
8
+ const body = { ...current };
9
+ for (const [key, value] of Object.entries(changes)) {
10
+ if (value !== undefined)
11
+ body[key] = value;
12
+ }
13
+ return body;
14
+ }
15
+ /** Refuses a --name that is present but blank, which a full-replace PUT would otherwise store. */
16
+ export function assertNameNotBlank(name) {
17
+ if (name !== undefined && !name.trim())
18
+ throw new Error("--name must not be empty.");
19
+ }
20
+ //# sourceMappingURL=overlay.js.map
@@ -0,0 +1,19 @@
1
+ import type { SkillsApplyPreview } from "./agent-run.js";
2
+ /** The grant's consequence for a SkillsApply change (spec §6, D13), shown next to "approve and Remember". */
3
+ export declare const REMEMBER_NOTE = "approve and Remember: later skill changes you make in this chat apply without asking";
4
+ /**
5
+ * A SkillsApply preview as plain text, one entry per line (#782, spec §10): per skill where it
6
+ * starts and the labels it moves, each file with its unified diff indented under it, then the
7
+ * followers snapshot and the binding. Lines are unstyled and unstripped; the prompt does both.
8
+ * The generated type marks every field optional and the wire sends nulls, so every read is guarded.
9
+ */
10
+ export declare function previewLines(preview: SkillsApplyPreview): string[];
11
+ /**
12
+ * Whether the preview leaves part of the change unseen (#782, spec D7): a skill with files left
13
+ * out, a diff that was cut, or an add or edit with no diff at all (abandoned as too large, or a
14
+ * base the server could not read). The prompt then prints the full arguments as well, because a
15
+ * change that persists must be readable at the prompt. A `put` or `delete` carries no diff by
16
+ * design and does not count. Guarded like {@link previewLines}: every field optional, nulls on the wire.
17
+ */
18
+ export declare function previewIsIncomplete(preview: SkillsApplyPreview): boolean;
19
+ //# sourceMappingURL=skills-apply-preview.d.ts.map
@@ -0,0 +1,94 @@
1
+ /** The grant's consequence for a SkillsApply change (spec §6, D13), shown next to "approve and Remember". */
2
+ export const REMEMBER_NOTE = "approve and Remember: later skill changes you make in this chat apply without asking";
3
+ const OP_WORDS = { add: "new file", edit: "edited", delete: "deleted", put: "uploaded file" };
4
+ /**
5
+ * A SkillsApply preview as plain text, one entry per line (#782, spec §10): per skill where it
6
+ * starts and the labels it moves, each file with its unified diff indented under it, then the
7
+ * followers snapshot and the binding. Lines are unstyled and unstripped; the prompt does both.
8
+ * The generated type marks every field optional and the wire sends nulls, so every read is guarded.
9
+ */
10
+ export function previewLines(preview) {
11
+ const lines = ["Skill changes:"];
12
+ for (const skill of list(preview.skills)) {
13
+ const name = String(skill.name ?? "");
14
+ const from = typeof skill.from === "number" ? skill.from : null;
15
+ const moves = list(skill.moves).map(String);
16
+ const start = from === null ? `${name}: new skill` : `${name} v${from} -> new version`;
17
+ lines.push(` ${start}${moves.length > 0 ? `, moves ${moves.join(", ")}` : ""}`);
18
+ if (typeof skill.fork_of_plugin === "string" && skill.fork_of_plugin) {
19
+ lines.push(` forks the plugin skill from ${skill.fork_of_plugin}: later plugin syncs no longer move latest`);
20
+ }
21
+ for (const file of list(skill.files))
22
+ lines.push(...fileLines(file));
23
+ const omitted = typeof skill.files_omitted === "number" ? skill.files_omitted : 0;
24
+ if (omitted > 0)
25
+ lines.push(` ${omitted} more ${omitted === 1 ? "file" : "files"} not shown`);
26
+ }
27
+ const followers = preview.followers;
28
+ if (followers) {
29
+ const agents = list(followers.agents).map(String);
30
+ const more = typeof followers.more === "number" ? followers.more : 0;
31
+ const when = typeof followers.as_of === "string" ? ` (as of ${followers.as_of})` : "";
32
+ if (agents.length === 0 && more === 0)
33
+ lines.push(`No agent follows these labels${when}`);
34
+ else
35
+ lines.push(`Agents following these labels${when}: ${agents.length > 0 ? agents.join(", ") : `${more} agents`}${agents.length > 0 && more > 0 ? ` and ${more} more` : ""}`);
36
+ }
37
+ const agent = preview.agent;
38
+ const bind = agent ? list(agent.bind).map(String) : [];
39
+ if (agent && bind.length > 0) {
40
+ const base = typeof agent.from === "number" ? ` (new agent version from v${agent.from})` : "";
41
+ lines.push(`Binds ${bind.join(", ")} to this agent${base}`);
42
+ }
43
+ return lines;
44
+ }
45
+ /**
46
+ * Whether the preview leaves part of the change unseen (#782, spec D7): a skill with files left
47
+ * out, a diff that was cut, or an add or edit with no diff at all (abandoned as too large, or a
48
+ * base the server could not read). The prompt then prints the full arguments as well, because a
49
+ * change that persists must be readable at the prompt. A `put` or `delete` carries no diff by
50
+ * design and does not count. Guarded like {@link previewLines}: every field optional, nulls on the wire.
51
+ */
52
+ export function previewIsIncomplete(preview) {
53
+ for (const skill of list(preview.skills)) {
54
+ if (typeof skill.files_omitted === "number" && skill.files_omitted > 0)
55
+ return true;
56
+ for (const file of list(skill.files)) {
57
+ if (file.truncated === true)
58
+ return true;
59
+ if ((file.op === "add" || file.op === "edit") && typeof file.diff !== "string")
60
+ return true;
61
+ }
62
+ }
63
+ return false;
64
+ }
65
+ function fileLines(file) {
66
+ const facts = [OP_WORDS[String(file.op)] ?? String(file.op)];
67
+ if (typeof file.added === "number" && typeof file.removed === "number")
68
+ facts.push(`+${file.added} -${file.removed}`);
69
+ if (typeof file.bytes === "number")
70
+ facts.push(size(file.bytes));
71
+ const lines = [` ${String(file.path ?? "")}: ${facts.join(", ")}`];
72
+ const diff = typeof file.diff === "string" ? file.diff : null;
73
+ if (diff !== null) {
74
+ for (const line of diff.split("\n"))
75
+ lines.push(` ${line}`);
76
+ if (file.truncated === true)
77
+ lines.push(" (diff cut; the counts cover every changed line)");
78
+ }
79
+ else if (file.truncated === true) {
80
+ lines.push(` too many changes to show: at most +${Number(file.added ?? 0)} -${Number(file.removed ?? 0)} lines`);
81
+ }
82
+ return lines;
83
+ }
84
+ function list(value) {
85
+ return Array.isArray(value) ? value.filter((entry) => entry !== null && entry !== undefined) : [];
86
+ }
87
+ function size(bytes) {
88
+ if (bytes < 1024)
89
+ return `${bytes} B`;
90
+ if (bytes < 1024 * 1024)
91
+ return `${Math.round(bytes / 1024)} KB`;
92
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
93
+ }
94
+ //# sourceMappingURL=skills-apply-preview.js.map
@@ -0,0 +1,26 @@
1
+ /** The options of `tracing settings set`, as commander hands them over. */
2
+ export interface TracingSettingsOptions {
3
+ includePrompts?: string;
4
+ includeCompletions?: string;
5
+ retentionDays?: string;
6
+ }
7
+ /** The fields of a GET this command carries through. */
8
+ export interface TracingSettingsCurrent {
9
+ includePrompts?: boolean;
10
+ includeCompletions?: boolean;
11
+ retentionDays?: number | null;
12
+ }
13
+ export interface TracingSettingsBody {
14
+ includePrompts: boolean;
15
+ includeCompletions: boolean;
16
+ retentionDays: number | null;
17
+ }
18
+ /**
19
+ * The PUT body: the options given, and the current value of everything else. The PUT is a
20
+ * full replace (#1015), so a field left out would reset: a missing retentionDays would
21
+ * follow the plan again and undo the admin's shorter choice.
22
+ */
23
+ export declare function tracingSettingsBody(current: TracingSettingsCurrent | undefined, opts: TracingSettingsOptions): TracingSettingsBody;
24
+ /** `plan` follows the plan's limit; anything else must be a whole number of days, 1 or more. */
25
+ export declare function parseRetentionDays(value: string): number | null;
26
+ //# sourceMappingURL=tracing-settings.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { CliUsageError } from "./errors.js";
2
+ /**
3
+ * The PUT body: the options given, and the current value of everything else. The PUT is a
4
+ * full replace (#1015), so a field left out would reset: a missing retentionDays would
5
+ * follow the plan again and undo the admin's shorter choice.
6
+ */
7
+ export function tracingSettingsBody(current, opts) {
8
+ return {
9
+ includePrompts: opts.includePrompts !== undefined ? opts.includePrompts === "true" : (current?.includePrompts ?? false),
10
+ includeCompletions: opts.includeCompletions !== undefined
11
+ ? opts.includeCompletions === "true"
12
+ : (current?.includeCompletions ?? false),
13
+ retentionDays: opts.retentionDays !== undefined ? parseRetentionDays(opts.retentionDays) : (current?.retentionDays ?? null),
14
+ };
15
+ }
16
+ /** `plan` follows the plan's limit; anything else must be a whole number of days, 1 or more. */
17
+ export function parseRetentionDays(value) {
18
+ if (value === "plan")
19
+ return null;
20
+ if (!/^[1-9]\d*$/.test(value)) {
21
+ throw new CliUsageError(`--retention-days must be a whole number of days (1 or more) or "plan", got "${value}".`);
22
+ }
23
+ return Number(value);
24
+ }
25
+ //# sourceMappingURL=tracing-settings.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2kw/ai",
3
- "version": "6.3.0-dev.12",
3
+ "version": "6.3.0-dev.122",
4
4
  "description": "CLI for 2kw.ai — schema-driven document extraction, an OpenAI-compatible EU LLM gateway, transcription, prompts, datasets, and experiments from your terminal or agentic workflows. Ships as 2kw, backbone, and bb.",
5
5
  "keywords": [
6
6
  "cli",