@2kw/ai 7.4.0-dev.1 → 7.4.0-dev.11

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 CHANGED
@@ -75,8 +75,8 @@ Explicit API keys always take priority over a stored browser session
75
75
  ```
76
76
 
77
77
  Note: `config get apiKey --json` returns a masked value — stored secrets do
78
- not round-trip through stdout. Scripts needing the raw key should use
79
- `AI_2KW_API_KEY` or read the config file (path shown by `config list`).
78
+ not round-trip through stdout by default. Scripts needing the raw key pass
79
+ `--reveal` (`config get apiKey --reveal`) or use `AI_2KW_API_KEY`.
80
80
 
81
81
  ## Contexts
82
82
 
@@ -52,6 +52,9 @@ export function makeAgentPolicyCommand() {
52
52
  `auto-approval ${auto?.enabled ? "on" : "off (every auto pauses for a human)"}`,
53
53
  `judge ${auto?.judgeConfigured ? "configured" : "not configured (every candidate escalates)"}`,
54
54
  ];
55
+ if (auto?.instructionsExceedJudgeBound) {
56
+ parts.push("instructions longer than the judge reads (every candidate escalates)");
57
+ }
55
58
  if (mode)
56
59
  parts.push(`mode ${mode}`);
57
60
  if (data?.catalogResolvedAt)
@@ -86,14 +86,15 @@ export function makeConfigCommand() {
86
86
  .command("get")
87
87
  .description("Get a configuration value")
88
88
  .argument("<key>", `Config key (${ALLOWED_KEYS.join(", ")})`)
89
- .action((key, _opts, command) => {
89
+ .option("--reveal", "Print the API key unmasked (for scripts that need the key itself)")
90
+ .action((key, opts, command) => {
90
91
  const validKey = validateKey(key);
91
92
  const ctx = getActiveContext();
92
93
  const raw = ctx?.[validKey];
93
94
  // A stored "" apiKey stays "" (shown as "(not set)"); only a real key is masked.
94
95
  const value = raw === undefined
95
96
  ? undefined
96
- : validKey === "apiKey" && typeof raw === "string"
97
+ : validKey === "apiKey" && typeof raw === "string" && !opts.reveal
97
98
  ? raw && maskApiKey(raw)
98
99
  : String(raw);
99
100
  if (isJsonOutput(command)) {
@@ -17,13 +17,22 @@ function formatComparisonCell(result) {
17
17
  const scores = result.scores ?? [];
18
18
  if (scores.length > 0) {
19
19
  // A SKIP carries a placeholder 0.0 that is not a rating, and a comment-only
20
- // score has no number; neither takes part in the average (#693).
21
- const rated = scores.filter((s) => s.label !== "SKIP" && s.score != null);
20
+ // score rates nothing; neither is picked (#693). Of the rest, one score per
21
+ // evaluator, as the console's pickCellScore: HUMAN, then LLM_JUDGE, then the
22
+ // first, so an override replaces the score it supersedes (#1410).
23
+ const byEvaluator = new Map();
24
+ for (const s of scores) {
25
+ if (s.label === "SKIP" || (s.score == null && !s.label))
26
+ continue;
27
+ byEvaluator.set(s.evaluatorId, [...(byEvaluator.get(s.evaluatorId) ?? []), s]);
28
+ }
29
+ const picked = [...byEvaluator.values()].map((group) => group.find((s) => s.source === "HUMAN") ?? group.find((s) => s.source === "LLM_JUDGE") ?? group[0]);
30
+ const rated = picked.filter((s) => s.score != null);
22
31
  if (rated.length > 0) {
23
32
  return (rated.reduce((sum, s) => sum + s.score, 0) / rated.length).toFixed(2);
24
33
  }
25
34
  // A label-only verdict (#1163) has no number; show its label, as the console does.
26
- const verdict = scores.find((s) => s.label && s.label !== "SKIP");
35
+ const verdict = picked[0];
27
36
  if (verdict)
28
37
  return String(verdict.label);
29
38
  if (scores.every((s) => s.label === "SKIP"))
@@ -102,6 +102,7 @@ const CODE_HINTS = {
102
102
  "Check pendingToolCalls and pendingApprovals in the run envelope.",
103
103
  unknown_tool_output: "That call id was not released by this response. Use the responseId of the latest envelope.",
104
104
  conversation_agent_mismatch: "This conversation belongs to another agent. Start a new conversation or run the agent that owns it.",
105
+ provider_quota_exhausted: "The model provider account is out of credits or at its spend limit. Add credits or raise the limit with the provider; retrying will not help.",
105
106
  };
106
107
  /** The most specific hint for an API error: gateway code, then known messages, then the status table. */
107
108
  export function hintFor(err) {
@@ -114,7 +115,7 @@ export function hintFor(err) {
114
115
  if (err.headResponseId) {
115
116
  return `The run's newest response is ${err.headResponseId}. Check it: 2kw responses get ${err.headResponseId}`;
116
117
  }
117
- if (err.code && CODE_HINTS[err.code])
118
+ if (err.code && Object.hasOwn(CODE_HINTS, err.code))
118
119
  return CODE_HINTS[err.code];
119
120
  // The gateway answers `agent_not_published` (code), the REST layer AGENT_NOT_PUBLISHED (errorCode).
120
121
  if (err.code === "agent_not_published" || err.errorCode === "AGENT_NOT_PUBLISHED") {
@@ -27,6 +27,11 @@ export declare const POLL_WAIT_SECONDS = 25;
27
27
  export declare const ACCEPTANCE_MS = 10000;
28
28
  export declare const OWNER_LEASE_MS = 30000;
29
29
  export declare const OFFLINE_MS = 60000;
30
+ /**
31
+ * How often a relay refreshes the backend's signing keys on its own. The hub uses it to decide how
32
+ * long a JWKS refresh hint stays relevant for a relay it first sees later (#801).
33
+ */
34
+ export declare const JWKS_REFRESH_INTERVAL_MS: number;
30
35
  export declare const CALL_TOTAL_MS: number;
31
36
  export declare const LISTEN_TOTAL_MS: number;
32
37
  export declare const MAX_HEAD_DEADLINE_MS: number;
@@ -29,6 +29,11 @@ export const POLL_WAIT_SECONDS = 25;
29
29
  export const ACCEPTANCE_MS = 10_000;
30
30
  export const OWNER_LEASE_MS = 30_000;
31
31
  export const OFFLINE_MS = 60_000;
32
+ /**
33
+ * How often a relay refreshes the backend's signing keys on its own. The hub uses it to decide how
34
+ * long a JWKS refresh hint stays relevant for a relay it first sees later (#801).
35
+ */
36
+ export const JWKS_REFRESH_INTERVAL_MS = 10 * 60_000;
32
37
  export const CALL_TOTAL_MS = 10 * 60_000;
33
38
  export const LISTEN_TOTAL_MS = 60 * 60_000;
34
39
  export const MAX_HEAD_DEADLINE_MS = 10 * 60_000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2kw/ai",
3
- "version": "7.4.0-dev.1",
3
+ "version": "7.4.0-dev.11",
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",