@kindgi/dev-echo-provider 0.1.4-rc.3 → 0.1.4-rc.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.
package/README.md CHANGED
@@ -14,6 +14,19 @@ Emits a two-message script (tool-call → text):
14
14
  2. **Second invocation** (post-tool) — emits a final assistant message:
15
15
  `Tool responded: <tool result>`.
16
16
 
17
+ **It says it isn't a model.** Every text answer starts with one line,
18
+ `DEV_ECHO_WARNING_LINE`:
19
+
20
+ ```text
21
+ ⚠ dev-echo isn't a real model: it only repeats what it's given. Add an LLM provider key (Anthropic, OpenAI, Gemini, Groq, OpenRouter…) to get real answers.
22
+ ```
23
+
24
+ An answer that is JSON (what a typed-output agent parses; dev-echo hands
25
+ back the JSON it was given) stays bare, as does one asked for with
26
+ `structuredOutput`. Every result also carries `warnings: [DEV_ECHO_WARNING]`
27
+ (code `dev-echo-not-a-model`, with the commands that add a model), which an
28
+ agent turn collects into its result's `warnings`.
29
+
17
30
  State lives in the message trail, not on the instance — safe to share
18
31
  across concurrent runs.
19
32
 
package/dist/index.d.ts CHANGED
@@ -15,14 +15,29 @@
15
15
  * itself — so a typed-output agent handed JSON gets that JSON back.
16
16
  * - On the second invocation (post-tool) it emits a final assistant
17
17
  * message: `Tool responded: <tool result>`.
18
+ * - Every text answer starts with `DEV_ECHO_WARNING_LINE`, and every
19
+ * result carries `DEV_ECHO_WARNING` (`dev-echo-not-a-model`), so no one
20
+ * mistakes it for a model. A JSON answer (what a typed-output agent
21
+ * parses) and a `structuredOutput` one stay bare.
18
22
  *
19
23
  * State lives per-invocation — the provider inspects the message trail,
20
24
  * not an instance variable, so it is safe to share across concurrent
21
25
  * runs.
22
26
  */
23
- import type { ModelProvider, ProviderMetadata } from '@kindgi/capabilities';
27
+ import type { ModelCallWarning, ModelProvider, ProviderMetadata } from '@kindgi/capabilities';
24
28
  export declare const DEV_ECHO_PROVIDER_ID = "dev-echo";
25
29
  export declare const DEV_ECHO_MODEL_NAME = "dev-echo-v1";
30
+ /** The code of the warning every dev-echo answer carries (`ModelCallResult.warnings`). */
31
+ export declare const DEV_ECHO_WARNING_CODE = "dev-echo-not-a-model";
32
+ /**
33
+ * The first line of every dev-echo text answer: it isn't a model, and what
34
+ * to do. A JSON answer stays bare (a typed-output agent parses it: echo
35
+ * hands back the JSON it was given), as does one asked for with
36
+ * `structuredOutput`; the warning in `warnings` says the same there.
37
+ */
38
+ export declare const DEV_ECHO_WARNING_LINE = "\u26A0 dev-echo isn't a real model: it only repeats what it's given. Add an LLM provider key (Anthropic, OpenAI, Gemini, Groq, OpenRouter\u2026) to get real answers.";
39
+ /** The warning, with the commands that add a model. */
40
+ export declare const DEV_ECHO_WARNING: ModelCallWarning;
26
41
  /**
27
42
  * Build the deterministic dev-echo provider. The returned value is a
28
43
  * plain `ModelProvider` — pass it to `createProviderRegistry([...])` or
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAGV,aAAa,EACb,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAC/C,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AAuCjD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,aAAa,CAkDrD;AAED;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,gBAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAGV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAC/C,eAAO,MAAM,mBAAmB,gBAAgB,CAAC;AAuBjD,0FAA0F;AAC1F,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,0KAC6H,CAAC;AAEhK,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,EAAE,gBAI9B,CAAC;AAoCF;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,aAAa,CAqDrD;AAED;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,gBAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -20,6 +20,39 @@ const METADATA = {
20
20
  fallback: true,
21
21
  };
22
22
  const TOOL_CALL_ID = 'dev-echo-call-1';
23
+ /** The code of the warning every dev-echo answer carries (`ModelCallResult.warnings`). */
24
+ export const DEV_ECHO_WARNING_CODE = 'dev-echo-not-a-model';
25
+ /**
26
+ * The first line of every dev-echo text answer: it isn't a model, and what
27
+ * to do. A JSON answer stays bare (a typed-output agent parses it: echo
28
+ * hands back the JSON it was given), as does one asked for with
29
+ * `structuredOutput`; the warning in `warnings` says the same there.
30
+ */
31
+ export const DEV_ECHO_WARNING_LINE = "⚠ dev-echo isn't a real model: it only repeats what it's given. Add an LLM provider key (Anthropic, OpenAI, Gemini, Groq, OpenRouter…) to get real answers.";
32
+ /** The warning, with the commands that add a model. */
33
+ export const DEV_ECHO_WARNING = {
34
+ code: DEV_ECHO_WARNING_CODE,
35
+ message: "dev-echo answered, and it isn't a real model: it only repeats what it's given. Add an LLM provider key: kindgi secrets set <KEY> --env=local --scope=tenant (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY…), then kindgi providers register --preset=<anthropic|openai|gemini-api|groq|openrouter>. kindgi providers presets lists them.",
36
+ };
37
+ /** An answer that is a JSON object or array: what a typed-output agent parses. */
38
+ function isJsonAnswer(text) {
39
+ const t = text.trim();
40
+ if (!(t.startsWith('{') || t.startsWith('[')))
41
+ return false;
42
+ try {
43
+ JSON.parse(t);
44
+ return true;
45
+ }
46
+ catch {
47
+ return false;
48
+ }
49
+ }
50
+ /** A text answer, with the warning line first; a typed (JSON) answer as it is. */
51
+ function answerText(input, text) {
52
+ if (input.structuredOutput !== undefined || isJsonAnswer(text))
53
+ return text;
54
+ return `${DEV_ECHO_WARNING_LINE}\n\n${text}`;
55
+ }
23
56
  function lastUserMessage(input) {
24
57
  for (let i = input.messages.length - 1; i >= 0; i -= 1) {
25
58
  const m = input.messages[i];
@@ -49,12 +82,13 @@ export function createDevEchoProvider() {
49
82
  const toolName = input.tools?.[0]?.name;
50
83
  if (toolResult === null && toolName === undefined) {
51
84
  return {
52
- message: { role: 'assistant', content: lastUserMessage(input) },
85
+ message: { role: 'assistant', content: answerText(input, lastUserMessage(input)) },
53
86
  finishReason: 'stop',
54
87
  usage: { promptTokens: 20, completionTokens: 6 },
55
88
  costUsd: 0,
56
89
  durationMs: 1,
57
90
  provider: { id: METADATA.id, model: DEV_ECHO_MODEL_NAME },
91
+ warnings: [DEV_ECHO_WARNING],
58
92
  };
59
93
  }
60
94
  if (toolResult === null && toolName !== undefined) {
@@ -76,18 +110,20 @@ export function createDevEchoProvider() {
76
110
  costUsd: 0,
77
111
  durationMs: 1,
78
112
  provider: { id: METADATA.id, model: DEV_ECHO_MODEL_NAME },
113
+ warnings: [DEV_ECHO_WARNING],
79
114
  };
80
115
  }
81
116
  return {
82
117
  message: {
83
118
  role: 'assistant',
84
- content: `Tool responded: ${toolResult}`,
119
+ content: answerText(input, `Tool responded: ${toolResult}`),
85
120
  },
86
121
  finishReason: 'stop',
87
122
  usage: { promptTokens: 30, completionTokens: 12 },
88
123
  costUsd: 0,
89
124
  durationMs: 1,
90
125
  provider: { id: METADATA.id, model: DEV_ECHO_MODEL_NAME },
126
+ warnings: [DEV_ECHO_WARNING],
91
127
  };
92
128
  },
93
129
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kindgi/dev-echo-provider",
3
- "version": "0.1.4-rc.3",
3
+ "version": "0.1.4-rc.4",
4
4
  "description": "Deterministic dev-only ModelProvider — no LLM key, no network, no cost. Emits a two-message scripted response (tool-call → text) so an agent turn completes in milliseconds. For dev, tests and tutorials. NEVER for production — every real deployment plugs in a real model provider adapter (Anthropic, OpenAI-compat, etc.) instead.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -28,7 +28,7 @@
28
28
  "README.md"
29
29
  ],
30
30
  "dependencies": {
31
- "@kindgi/capabilities": "0.1.4-rc.3"
31
+ "@kindgi/capabilities": "0.1.4-rc.4"
32
32
  },
33
33
  "engines": {
34
34
  "node": ">=22.12.0"
package/src/index.ts CHANGED
@@ -18,6 +18,10 @@
18
18
  * itself — so a typed-output agent handed JSON gets that JSON back.
19
19
  * - On the second invocation (post-tool) it emits a final assistant
20
20
  * message: `Tool responded: <tool result>`.
21
+ * - Every text answer starts with `DEV_ECHO_WARNING_LINE`, and every
22
+ * result carries `DEV_ECHO_WARNING` (`dev-echo-not-a-model`), so no one
23
+ * mistakes it for a model. A JSON answer (what a typed-output agent
24
+ * parses) and a `structuredOutput` one stay bare.
21
25
  *
22
26
  * State lives per-invocation — the provider inspects the message trail,
23
27
  * not an instance variable, so it is safe to share across concurrent
@@ -27,6 +31,7 @@
27
31
  import type {
28
32
  ModelCallInput,
29
33
  ModelCallResult,
34
+ ModelCallWarning,
30
35
  ModelProvider,
31
36
  ProviderMetadata,
32
37
  } from '@kindgi/capabilities';
@@ -55,6 +60,43 @@ const METADATA: ProviderMetadata = {
55
60
 
56
61
  const TOOL_CALL_ID = 'dev-echo-call-1';
57
62
 
63
+ /** The code of the warning every dev-echo answer carries (`ModelCallResult.warnings`). */
64
+ export const DEV_ECHO_WARNING_CODE = 'dev-echo-not-a-model';
65
+
66
+ /**
67
+ * The first line of every dev-echo text answer: it isn't a model, and what
68
+ * to do. A JSON answer stays bare (a typed-output agent parses it: echo
69
+ * hands back the JSON it was given), as does one asked for with
70
+ * `structuredOutput`; the warning in `warnings` says the same there.
71
+ */
72
+ export const DEV_ECHO_WARNING_LINE =
73
+ "⚠ dev-echo isn't a real model: it only repeats what it's given. Add an LLM provider key (Anthropic, OpenAI, Gemini, Groq, OpenRouter…) to get real answers.";
74
+
75
+ /** The warning, with the commands that add a model. */
76
+ export const DEV_ECHO_WARNING: ModelCallWarning = {
77
+ code: DEV_ECHO_WARNING_CODE,
78
+ message:
79
+ "dev-echo answered, and it isn't a real model: it only repeats what it's given. Add an LLM provider key: kindgi secrets set <KEY> --env=local --scope=tenant (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY…), then kindgi providers register --preset=<anthropic|openai|gemini-api|groq|openrouter>. kindgi providers presets lists them.",
80
+ };
81
+
82
+ /** An answer that is a JSON object or array: what a typed-output agent parses. */
83
+ function isJsonAnswer(text: string): boolean {
84
+ const t = text.trim();
85
+ if (!(t.startsWith('{') || t.startsWith('['))) return false;
86
+ try {
87
+ JSON.parse(t);
88
+ return true;
89
+ } catch {
90
+ return false;
91
+ }
92
+ }
93
+
94
+ /** A text answer, with the warning line first; a typed (JSON) answer as it is. */
95
+ function answerText(input: ModelCallInput, text: string): string {
96
+ if (input.structuredOutput !== undefined || isJsonAnswer(text)) return text;
97
+ return `${DEV_ECHO_WARNING_LINE}\n\n${text}`;
98
+ }
99
+
58
100
  function lastUserMessage(input: ModelCallInput): string {
59
101
  for (let i = input.messages.length - 1; i >= 0; i -= 1) {
60
102
  const m = input.messages[i];
@@ -84,12 +126,13 @@ export function createDevEchoProvider(): ModelProvider {
84
126
  const toolName = input.tools?.[0]?.name;
85
127
  if (toolResult === null && toolName === undefined) {
86
128
  return {
87
- message: { role: 'assistant', content: lastUserMessage(input) },
129
+ message: { role: 'assistant', content: answerText(input, lastUserMessage(input)) },
88
130
  finishReason: 'stop',
89
131
  usage: { promptTokens: 20, completionTokens: 6 },
90
132
  costUsd: 0,
91
133
  durationMs: 1,
92
134
  provider: { id: METADATA.id, model: DEV_ECHO_MODEL_NAME },
135
+ warnings: [DEV_ECHO_WARNING],
93
136
  };
94
137
  }
95
138
  if (toolResult === null && toolName !== undefined) {
@@ -111,18 +154,20 @@ export function createDevEchoProvider(): ModelProvider {
111
154
  costUsd: 0,
112
155
  durationMs: 1,
113
156
  provider: { id: METADATA.id, model: DEV_ECHO_MODEL_NAME },
157
+ warnings: [DEV_ECHO_WARNING],
114
158
  };
115
159
  }
116
160
  return {
117
161
  message: {
118
162
  role: 'assistant',
119
- content: `Tool responded: ${toolResult}`,
163
+ content: answerText(input, `Tool responded: ${toolResult}`),
120
164
  },
121
165
  finishReason: 'stop',
122
166
  usage: { promptTokens: 30, completionTokens: 12 },
123
167
  costUsd: 0,
124
168
  durationMs: 1,
125
169
  provider: { id: METADATA.id, model: DEV_ECHO_MODEL_NAME },
170
+ warnings: [DEV_ECHO_WARNING],
126
171
  };
127
172
  },
128
173
  };