theokit 0.13.0 → 0.14.0
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/dist/{actions-virtual-module-EIPXX4ZB.js → actions-virtual-module-RM7JRY5N.js} +7 -7
- package/dist/{app-typed-client-7PBFWZUE.js → app-typed-client-5VQE6DNF.js} +7 -7
- package/dist/boot/index.js +3 -3
- package/dist/{build-HXND27XG.js → build-5K7LK77K.js} +2 -2
- package/dist/{chunk-3S3BNW5K.js → chunk-5UUOGAJH.js} +2 -2
- package/dist/{chunk-O62MW4MT.js → chunk-637WJB7Z.js} +2 -2
- package/dist/{chunk-TGTNRUH3.js → chunk-H243MR3F.js} +2 -2
- package/dist/{chunk-NHJMZCAS.js → chunk-JZHT3LW7.js} +1 -1
- package/dist/chunk-JZHT3LW7.js.map +1 -0
- package/dist/chunk-KGFNWIMS.js +94 -0
- package/dist/chunk-KGFNWIMS.js.map +1 -0
- package/dist/{chunk-RYTZYFSD.js → chunk-RBHCJHRR.js} +65 -28
- package/dist/chunk-RBHCJHRR.js.map +1 -0
- package/dist/{chunk-UNLA45FY.js → chunk-S7Y5WLZY.js} +1 -1
- package/dist/chunk-S7Y5WLZY.js.map +1 -0
- package/dist/{chunk-WFNLNIJX.js → chunk-Z5IGLBWE.js} +1 -1
- package/dist/cli/index.js +3 -3
- package/dist/client/index.d.ts +3 -152
- package/dist/client/index.js +13 -236
- package/dist/client/index.js.map +1 -1
- package/dist/{dev-OWW4XVIH.js → dev-QOEVYNBG.js} +3 -3
- package/dist/index.js +12 -13
- package/dist/index.js.map +1 -1
- package/dist/{internal-api-4YTJDITC.js → internal-api-5BDI6N5U.js} +20 -20
- package/dist/server/auth/index.js +1 -1
- package/dist/server/define/index.d.ts +3 -70
- package/dist/server/define/index.js +2 -4
- package/dist/server/http/index.js +2 -2
- package/dist/server/index.d.ts +1 -3
- package/dist/server/index.js +90 -105
- package/dist/server/index.js.map +1 -1
- package/dist/server/jobs/index.js +4 -4
- package/dist/server/observability/index.js +1 -1
- package/dist/server/scan/index.js +1 -1
- package/dist/{start-KIQ5TTLR.js → start-2KG4JSXM.js} +2 -2
- package/dist/vite-plugin/index.js +12 -13
- package/dist/{vite-plugin-RK66K26Z.js → vite-plugin-TDIDZ5U7.js} +3 -3
- package/package.json +1 -5
- package/dist/agent-events-DosDXkSV.d.ts +0 -94
- package/dist/chunk-2KZQPDYR.js +0 -226
- package/dist/chunk-2KZQPDYR.js.map +0 -1
- package/dist/chunk-EXP56GFQ.js +0 -52
- package/dist/chunk-EXP56GFQ.js.map +0 -1
- package/dist/chunk-NHJMZCAS.js.map +0 -1
- package/dist/chunk-RYTZYFSD.js.map +0 -1
- package/dist/chunk-UNLA45FY.js.map +0 -1
- package/dist/chunk-ZSTZXR2D.js +0 -208
- package/dist/chunk-ZSTZXR2D.js.map +0 -1
- package/dist/server/agent/index.d.ts +0 -229
- package/dist/server/agent/index.js +0 -17
- package/dist/vite-plugin-RK66K26Z.js.map +0 -1
- /package/dist/{actions-virtual-module-EIPXX4ZB.js.map → actions-virtual-module-RM7JRY5N.js.map} +0 -0
- /package/dist/{app-typed-client-7PBFWZUE.js.map → app-typed-client-5VQE6DNF.js.map} +0 -0
- /package/dist/{build-HXND27XG.js.map → build-5K7LK77K.js.map} +0 -0
- /package/dist/{chunk-3S3BNW5K.js.map → chunk-5UUOGAJH.js.map} +0 -0
- /package/dist/{chunk-O62MW4MT.js.map → chunk-637WJB7Z.js.map} +0 -0
- /package/dist/{chunk-TGTNRUH3.js.map → chunk-H243MR3F.js.map} +0 -0
- /package/dist/{chunk-WFNLNIJX.js.map → chunk-Z5IGLBWE.js.map} +0 -0
- /package/dist/{dev-OWW4XVIH.js.map → dev-QOEVYNBG.js.map} +0 -0
- /package/dist/{internal-api-4YTJDITC.js.map → internal-api-5BDI6N5U.js.map} +0 -0
- /package/dist/{start-KIQ5TTLR.js.map → start-2KG4JSXM.js.map} +0 -0
- /package/dist/{server/agent/index.js.map → vite-plugin-TDIDZ5U7.js.map} +0 -0
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* core/contracts/agent-events.ts
|
|
3
|
-
*
|
|
4
|
-
* Canonical home for the AgentEvent wire-format contract (T2.2 of
|
|
5
|
-
* architecture-cleanup plan; ADR-0001 v3 invariant #3 exception).
|
|
6
|
-
*
|
|
7
|
-
* Server emits via SSE; client consumes. Discriminated union by `type`.
|
|
8
|
-
* Both `server/agent/*` and `client/*` import from here.
|
|
9
|
-
*
|
|
10
|
-
* Per ADR-0001 v3: `cache → core/contracts`, `client → core/contracts`,
|
|
11
|
-
* `devtools → core/contracts` are LEGAL direct imports (this is the
|
|
12
|
-
* documented exception to the `no-cross-module-deep-import` rule).
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* Discriminated union for AgentRunError codes (Phase 1 — Production-Readiness #3).
|
|
16
|
-
*
|
|
17
|
-
* Mirrors `@theokit/sdk`'s `AgentRunErrorCode` without hard-importing the SDK
|
|
18
|
-
* type (D2 decoupling). EC-7 forward-compat: `(string & {})` fallback preserves
|
|
19
|
-
* autocompletion for the known codes while accepting future codes the SDK may
|
|
20
|
-
* introduce — autocomplete works AND TS doesn't reject unknown codes.
|
|
21
|
-
*/
|
|
22
|
-
type AgentRunErrorCode = 'auth' | 'rate_limit' | 'quota_exceeded' | 'invalid_model' | 'invalid_request' | 'invalid_input' | 'context_too_large' | 'safety_blocked' | 'provider_unreachable' | 'tool_runtime_error' | 'aborted' | 'unknown' | (string & {});
|
|
23
|
-
interface AgentMessageEvent {
|
|
24
|
-
type: 'message';
|
|
25
|
-
content: string;
|
|
26
|
-
/** Optional id for client-side dedup / animation keys. */
|
|
27
|
-
id?: string;
|
|
28
|
-
}
|
|
29
|
-
interface AgentToolCallEvent {
|
|
30
|
-
type: 'tool_call';
|
|
31
|
-
name: string;
|
|
32
|
-
args: Record<string, unknown>;
|
|
33
|
-
id?: string;
|
|
34
|
-
}
|
|
35
|
-
interface AgentToolResultEvent {
|
|
36
|
-
type: 'tool_result';
|
|
37
|
-
name: string;
|
|
38
|
-
data: unknown;
|
|
39
|
-
id?: string;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Error event emitted via SSE.
|
|
43
|
-
*
|
|
44
|
-
* Phase 1 — Production-Readiness #3:
|
|
45
|
-
* New optional fields `code/provider/retriable/retryAfterMs` discriminate
|
|
46
|
-
* error classes for client-side handling (auth → sign-in CTA; rate_limit →
|
|
47
|
-
* countdown; quota_exceeded → upsell; etc.).
|
|
48
|
-
*
|
|
49
|
-
* Backward compat (D4): all new fields are optional. Existing clients that
|
|
50
|
-
* read only `event.message` keep working unchanged. New clients can safely
|
|
51
|
-
* `switch (event.code)` — `undefined` (legacy server) is a valid case.
|
|
52
|
-
*
|
|
53
|
-
* EC-15 (DOCUMENT): `message` is *trusted* to not contain secrets. SDK's
|
|
54
|
-
* `AgentRunError.message` is propagated verbatim. The SDK's `providerError`
|
|
55
|
-
* is NEVER serialized into this event — quarantined to prevent leakage.
|
|
56
|
-
*/
|
|
57
|
-
interface AgentErrorEvent {
|
|
58
|
-
type: 'error';
|
|
59
|
-
message: string;
|
|
60
|
-
id?: string;
|
|
61
|
-
/** Discriminated error class — see AgentRunErrorCode. */
|
|
62
|
-
code?: AgentRunErrorCode;
|
|
63
|
-
/** Provider id (e.g., 'openai', 'anthropic', 'openrouter'). */
|
|
64
|
-
provider?: string;
|
|
65
|
-
/** Whether the SAME request can be retried as-is. */
|
|
66
|
-
retriable?: boolean;
|
|
67
|
-
/** Hint from provider's Retry-After header (milliseconds). Zero is valid (immediate retry). */
|
|
68
|
-
retryAfterMs?: number;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Extended thinking / reasoning event.
|
|
72
|
-
*
|
|
73
|
-
* Carries the model's reasoning text (when the model supports extended
|
|
74
|
-
* thinking). Mirrors the `@theokit/agents` stream-layer `ThinkingEvent`
|
|
75
|
-
* (`packages/agents/src/bridge/agent-stream-events.ts`) so the two layers
|
|
76
|
-
* agree on the wire form; defined here (not imported) to keep `core/contracts`
|
|
77
|
-
* free of a dependency on `@theokit/agents` (G1 dependency direction).
|
|
78
|
-
*
|
|
79
|
-
* Consumers that switch only on the other variants are unaffected (additive);
|
|
80
|
-
* a consumer that wants to surface reasoning opts in by handling `'thinking'`.
|
|
81
|
-
*/
|
|
82
|
-
interface AgentThinkingEvent {
|
|
83
|
-
type: 'thinking';
|
|
84
|
-
content: string;
|
|
85
|
-
/** Optional id for client-side dedup / animation keys. */
|
|
86
|
-
id?: string;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Runtime AgentEvent — discriminated union of the 5 variants emitted by
|
|
90
|
-
* agent endpoints. Server produces; client consumes.
|
|
91
|
-
*/
|
|
92
|
-
type AgentEvent = AgentMessageEvent | AgentToolCallEvent | AgentToolResultEvent | AgentErrorEvent | AgentThinkingEvent;
|
|
93
|
-
|
|
94
|
-
export type { AgentEvent as A, AgentErrorEvent as a, AgentMessageEvent as b, AgentThinkingEvent as c, AgentToolCallEvent as d, AgentToolResultEvent as e, AgentRunErrorCode as f };
|
package/dist/chunk-2KZQPDYR.js
DELETED
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
tryResolveProvider
|
|
3
|
-
} from "./chunk-EXP56GFQ.js";
|
|
4
|
-
|
|
5
|
-
// src/server/agent/stream-agent-run.ts
|
|
6
|
-
function safeJsonStringify(value) {
|
|
7
|
-
try {
|
|
8
|
-
return JSON.stringify(value);
|
|
9
|
-
} catch {
|
|
10
|
-
return "[Unserializable]";
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function safeArgs(args) {
|
|
14
|
-
if (typeof args === "object" && args !== null && !Array.isArray(args)) {
|
|
15
|
-
return args;
|
|
16
|
-
}
|
|
17
|
-
return {};
|
|
18
|
-
}
|
|
19
|
-
function isAssistant(msg) {
|
|
20
|
-
const m = msg;
|
|
21
|
-
return m.type === "assistant" && m.message != null && typeof m.message === "object" && Array.isArray(m.message.content);
|
|
22
|
-
}
|
|
23
|
-
function isToolCall(msg) {
|
|
24
|
-
const t = msg;
|
|
25
|
-
return t.type === "tool_call" && typeof t.name === "string" && typeof t.call_id === "string" && (t.status === "running" || t.status === "completed" || t.status === "error");
|
|
26
|
-
}
|
|
27
|
-
function isAgentRunError(err) {
|
|
28
|
-
if (!(err instanceof Error)) return false;
|
|
29
|
-
const e = err;
|
|
30
|
-
return "code" in e && typeof e.code === "string";
|
|
31
|
-
}
|
|
32
|
-
function errorToEvent(err, id) {
|
|
33
|
-
if (isAgentRunError(err)) {
|
|
34
|
-
const event2 = {
|
|
35
|
-
type: "error",
|
|
36
|
-
message: err.message,
|
|
37
|
-
code: err.code
|
|
38
|
-
};
|
|
39
|
-
if (err.provider !== void 0) event2.provider = err.provider;
|
|
40
|
-
if (err.retriable !== void 0) event2.retriable = err.retriable;
|
|
41
|
-
if (err.retryAfterMs !== void 0) event2.retryAfterMs = err.retryAfterMs;
|
|
42
|
-
if (id !== void 0) event2.id = id;
|
|
43
|
-
return event2;
|
|
44
|
-
}
|
|
45
|
-
let message;
|
|
46
|
-
if (err instanceof Error) {
|
|
47
|
-
message = err.message;
|
|
48
|
-
} else if (typeof err === "string") {
|
|
49
|
-
message = err;
|
|
50
|
-
} else if (err !== null && typeof err === "object" && "message" in err) {
|
|
51
|
-
const candidate = err.message;
|
|
52
|
-
message = typeof candidate === "string" ? candidate : "[object Object]";
|
|
53
|
-
} else if (err === null || err === void 0) {
|
|
54
|
-
message = String(err);
|
|
55
|
-
} else {
|
|
56
|
-
message = "[non-stringifiable error]";
|
|
57
|
-
}
|
|
58
|
-
const event = { type: "error", message };
|
|
59
|
-
if (id !== void 0) event.id = id;
|
|
60
|
-
return event;
|
|
61
|
-
}
|
|
62
|
-
function yieldFromToolCall(msg) {
|
|
63
|
-
if (msg.status === "running") {
|
|
64
|
-
return {
|
|
65
|
-
type: "tool_call",
|
|
66
|
-
name: msg.name,
|
|
67
|
-
args: safeArgs(msg.args),
|
|
68
|
-
id: msg.call_id
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
if (msg.status === "completed") {
|
|
72
|
-
const data = typeof msg.result === "string" ? msg.result : safeJsonStringify(msg.result);
|
|
73
|
-
return {
|
|
74
|
-
type: "tool_result",
|
|
75
|
-
name: msg.name,
|
|
76
|
-
data,
|
|
77
|
-
id: msg.call_id
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
const message = typeof msg.result === "string" ? msg.result : `Tool ${msg.name} failed`;
|
|
81
|
-
return { type: "error", message, id: msg.call_id };
|
|
82
|
-
}
|
|
83
|
-
async function* streamAgentRun(run) {
|
|
84
|
-
for await (const msg of run.stream()) {
|
|
85
|
-
if (isAssistant(msg)) {
|
|
86
|
-
for (const block of msg.message.content) {
|
|
87
|
-
if (block.type === "text" && typeof block.text === "string" && block.text.length > 0) {
|
|
88
|
-
yield { type: "message", content: block.text };
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
} else if (isToolCall(msg)) {
|
|
92
|
-
yield yieldFromToolCall(msg);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const result = await run.wait();
|
|
96
|
-
if (result.status === "error" && result.error !== void 0) {
|
|
97
|
-
yield errorToEvent(result.error);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// src/server/agent/create-conversation-history.ts
|
|
102
|
-
var sdkOverride = void 0;
|
|
103
|
-
function __setSdkForTests(sdk) {
|
|
104
|
-
sdkOverride = sdk;
|
|
105
|
-
}
|
|
106
|
-
function __resetSdkForTests() {
|
|
107
|
-
sdkOverride = void 0;
|
|
108
|
-
}
|
|
109
|
-
async function loadSdk() {
|
|
110
|
-
if (sdkOverride === null) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
"createConversationHistory requires @theokit/sdk. Install: pnpm add @theokit/sdk"
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
if (sdkOverride !== void 0) return sdkOverride;
|
|
116
|
-
try {
|
|
117
|
-
const { createRequire } = await import("module");
|
|
118
|
-
const requireFn = createRequire(import.meta.url);
|
|
119
|
-
const spec = "@theokit/sdk";
|
|
120
|
-
const mod = requireFn(spec);
|
|
121
|
-
return mod;
|
|
122
|
-
} catch (cause) {
|
|
123
|
-
throw new Error(
|
|
124
|
-
"createConversationHistory requires @theokit/sdk. Install: pnpm add @theokit/sdk",
|
|
125
|
-
{ cause }
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
var DEFAULT_COOKIE_NAME = "theo_conversation";
|
|
130
|
-
var DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
|
|
131
|
-
var AGENT_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/;
|
|
132
|
-
function isValidAgentId(s) {
|
|
133
|
-
return typeof s === "string" && AGENT_ID_REGEX.test(s);
|
|
134
|
-
}
|
|
135
|
-
function readCookieValue(request, name) {
|
|
136
|
-
let raw;
|
|
137
|
-
const h = request.headers;
|
|
138
|
-
if (h === void 0) return void 0;
|
|
139
|
-
if (typeof h.get === "function") {
|
|
140
|
-
raw = h.get("cookie") ?? void 0;
|
|
141
|
-
} else {
|
|
142
|
-
raw = h.cookie;
|
|
143
|
-
}
|
|
144
|
-
if (raw === void 0 || raw.length === 0) return void 0;
|
|
145
|
-
const pairs = raw.split(/[;,]/);
|
|
146
|
-
for (const pair of pairs) {
|
|
147
|
-
const eq = pair.indexOf("=");
|
|
148
|
-
if (eq < 0) continue;
|
|
149
|
-
const k = pair.slice(0, eq).trim();
|
|
150
|
-
if (k === name) return pair.slice(eq + 1).trim();
|
|
151
|
-
}
|
|
152
|
-
return void 0;
|
|
153
|
-
}
|
|
154
|
-
function serializeCookie(name, value, options) {
|
|
155
|
-
const parts = [`${name}=${value}`];
|
|
156
|
-
if (options.path !== void 0) parts.push(`Path=${options.path}`);
|
|
157
|
-
if (options.maxAge !== void 0) parts.push(`Max-Age=${options.maxAge}`);
|
|
158
|
-
if (options.sameSite !== void 0) {
|
|
159
|
-
const v = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1);
|
|
160
|
-
parts.push(`SameSite=${v}`);
|
|
161
|
-
}
|
|
162
|
-
if (options.httpOnly === true) parts.push("HttpOnly");
|
|
163
|
-
return parts.join("; ");
|
|
164
|
-
}
|
|
165
|
-
async function createConversationHistory(args) {
|
|
166
|
-
const cookieName = args.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
167
|
-
const rawMaxAge = args.cookieMaxAge;
|
|
168
|
-
const cookieMaxAge = typeof rawMaxAge === "number" && rawMaxAge > 0 ? rawMaxAge : DEFAULT_COOKIE_MAX_AGE;
|
|
169
|
-
let conversationId;
|
|
170
|
-
let isNew = false;
|
|
171
|
-
const cookieOnRequest = readCookieValue(args.request, cookieName);
|
|
172
|
-
if (isValidAgentId(args.agentId)) {
|
|
173
|
-
conversationId = args.agentId;
|
|
174
|
-
} else if (args.session !== null && args.session !== void 0) {
|
|
175
|
-
const sId = args.session.conversationId;
|
|
176
|
-
if (isValidAgentId(sId)) conversationId = sId;
|
|
177
|
-
}
|
|
178
|
-
if (conversationId === void 0 && isValidAgentId(cookieOnRequest)) {
|
|
179
|
-
conversationId = cookieOnRequest;
|
|
180
|
-
}
|
|
181
|
-
if (conversationId === void 0) {
|
|
182
|
-
conversationId = crypto.randomUUID();
|
|
183
|
-
isNew = true;
|
|
184
|
-
}
|
|
185
|
-
const shouldIssueCookie = isNew || cookieOnRequest !== conversationId;
|
|
186
|
-
if (shouldIssueCookie && args.response !== void 0) {
|
|
187
|
-
const cookie = serializeCookie(cookieName, conversationId, {
|
|
188
|
-
httpOnly: true,
|
|
189
|
-
sameSite: "lax",
|
|
190
|
-
maxAge: cookieMaxAge,
|
|
191
|
-
path: "/"
|
|
192
|
-
});
|
|
193
|
-
args.response.headers.append("set-cookie", cookie);
|
|
194
|
-
}
|
|
195
|
-
const resolvedOptions = autoResolveProviderIfNeeded(args.options);
|
|
196
|
-
const sdk = await loadSdk();
|
|
197
|
-
const agent = await sdk.Agent.getOrCreate(conversationId, resolvedOptions);
|
|
198
|
-
return { agent, conversationId, isNew };
|
|
199
|
-
}
|
|
200
|
-
function autoResolveProviderIfNeeded(options) {
|
|
201
|
-
if (typeof options.apiKey === "string" && options.apiKey.length > 0) {
|
|
202
|
-
return options;
|
|
203
|
-
}
|
|
204
|
-
const resolved = tryResolveProvider();
|
|
205
|
-
if (resolved === null) {
|
|
206
|
-
throw new Error(
|
|
207
|
-
"No LLM provider API key found in environment. Set OPENROUTER_API_KEY (recommended \u2014 gateway to many models) OR OPENAI_API_KEY OR ANTHROPIC_API_KEY in your .env. Get a free OpenRouter key at https://openrouter.ai/keys. (Pass `options.apiKey` explicitly to bypass auto-resolution.)"
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
...options,
|
|
212
|
-
apiKey: resolved.apiKey,
|
|
213
|
-
providers: {
|
|
214
|
-
routes: [{ capability: "chat", provider: resolved.name, baseUrl: resolved.baseUrl }]
|
|
215
|
-
}
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
export {
|
|
220
|
-
errorToEvent,
|
|
221
|
-
streamAgentRun,
|
|
222
|
-
__setSdkForTests,
|
|
223
|
-
__resetSdkForTests,
|
|
224
|
-
createConversationHistory
|
|
225
|
-
};
|
|
226
|
-
//# sourceMappingURL=chunk-2KZQPDYR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/agent/stream-agent-run.ts","../src/server/agent/create-conversation-history.ts"],"sourcesContent":["import type { AgentEvent, AgentErrorEvent } from './agent-types.js'\n\n/**\n * Item #4 — `streamAgentRun`\n *\n * Adapter that consumes the `@theokit/sdk` `Run.stream()` async generator\n * (SDKMessage variants) and yields TheoKit `AgentEvent`s suitable for SSE\n * via `defineAgentEndpoint`. One line at the consumer side:\n *\n * ```ts\n * const run = await agent.send(message)\n * yield* streamAgentRun(run)\n * ```\n *\n * Mapping table (SDK → AgentEvent):\n *\n * | SDK message | AgentEvent yielded |\n * |---|---|\n * | assistant.content[].type==='text' | { type: 'message', content } |\n * | assistant.content[].type==='tool_use'| (none — covered by tool_call below) |\n * | tool_call(status='running') | { type: 'tool_call', name, args, id } |\n * | tool_call(status='completed') | { type: 'tool_result', name, data, id }|\n * | tool_call(status='error') | { type: 'error', message, id } |\n * | run.wait() status==='error' | { type: 'error', message } |\n * | run.wait() status==='cancelled' | (none — cancel ≠ error) |\n * | system / user / thinking / status / | (none — internal SDK telemetry) |\n * | task / request / object_delta | |\n *\n * Abort semantics: when the consumer calls `generator.return()` on the\n * outer `defineAgentEndpoint` generator, `streamAgentRun` exits the\n * `for await` loop and does NOT call `run.wait()`. Cleanup of in-flight\n * SDK resources is the SDK consumer's responsibility (`run.cancel()`).\n */\n\n/**\n * Local mirror of the SDK's `Run` interface — only the surfaces we consume.\n * The message contract is minimal (just `{ type: string }`) so the SDK's\n * `SDKMessage` discriminated union IS structurally assignable without any\n * cast at the consumer site (covariant — TS accepts the SDK's typed message\n * as the wider `{ type: string }`). Property access inside `streamAgentRun`\n * narrows via runtime type guards.\n *\n * `import type` from `@theokit/sdk` would couple TheoKit to the SDK at type-\n * resolution time even for consumers who never use the agent surface.\n */\nexport interface AgentRunLike {\n stream: () => AsyncIterable<{ type: string }>\n wait: () => Promise<AgentRunResult>\n}\n\n/**\n * Re-exported as a convenience for test fixtures. Production code typically\n * passes an SDK `Run` directly (structural match via `{ type: string }`).\n */\nexport type AgentRunStreamMessage =\n | {\n type: 'assistant'\n message: { role: 'assistant'; content: { type: string; text?: string }[] }\n }\n | {\n type: 'tool_call'\n name: string\n status: 'running' | 'completed' | 'error'\n args?: unknown\n result?: unknown\n call_id: string\n }\n | { type: string; [k: string]: unknown }\n\n/** Subset of the SDK `RunResult` we consume. */\nexport interface AgentRunResult {\n status: 'finished' | 'error' | 'cancelled'\n error?: { message: string; code?: string; cause?: unknown }\n}\n\n/**\n * EC-1 (edge case review): tool result may be a Date, bigint, circular ref,\n * etc. `JSON.stringify` in `encodeSSE` would throw — uncaught inside the\n * outer generator — and `defineAgentEndpoint` would replace the legitimate\n * `tool_result` with a generic `error`. Coerce here so the wire stays honest.\n */\nfunction safeJsonStringify(value: unknown): string {\n try {\n return JSON.stringify(value)\n } catch {\n return '[Unserializable]'\n }\n}\n\n/**\n * EC-3 (edge case review): SDK types `args?: unknown`. A raw `as` cast hides\n * the possibility that `msg.args` is an array, primitive, or `null` (null\n * survives `??`). Type-guard BEFORE narrowing to `Record<string, unknown>`.\n */\nfunction safeArgs(args: unknown): Record<string, unknown> {\n if (typeof args === 'object' && args !== null && !Array.isArray(args)) {\n return args as Record<string, unknown>\n }\n return {}\n}\n\n/**\n * Yield AgentEvents derived from the SDK Run lifecycle.\n *\n * Consumer pattern:\n *\n * ```ts\n * export const POST = defineAgentEndpoint({\n * async *handler({ body }) {\n * const agent = await Agent.create({ apiKey, model, tools: [...] })\n * try {\n * const run = await agent.send(body.message)\n * yield* streamAgentRun(run)\n * } finally {\n * try { await agent.dispose() } catch (e) { console.warn(e) }\n * }\n * },\n * })\n * ```\n *\n * @public\n */\ninterface AssistantLike {\n type: 'assistant'\n message: { role: 'assistant'; content: { type: string; text?: string }[] }\n}\ninterface ToolCallLike {\n type: 'tool_call'\n name: string\n status: 'running' | 'completed' | 'error'\n args?: unknown\n result?: unknown\n call_id: string\n}\n\nfunction isAssistant(msg: { type: string }): msg is AssistantLike {\n // Wide cast to `unknown` first so runtime null guard survives ESLint\n // narrowing complaints — the SDK contract permits `null` even when its\n // TS type does not.\n const m = msg as unknown as {\n type: string\n message?: { content?: unknown } | null\n }\n return (\n m.type === 'assistant' &&\n m.message != null &&\n typeof m.message === 'object' &&\n Array.isArray(m.message.content)\n )\n}\nfunction isToolCall(msg: { type: string }): msg is ToolCallLike {\n const t = msg as unknown as {\n type: string\n name?: unknown\n status?: unknown\n call_id?: unknown\n }\n return (\n t.type === 'tool_call' &&\n typeof t.name === 'string' &&\n typeof t.call_id === 'string' &&\n (t.status === 'running' || t.status === 'completed' || t.status === 'error')\n )\n}\n\n/**\n * Phase 4 — Production-Readiness #3: structural mirror of SDK's AgentRunError.\n *\n * EC-6 (SHOULD TEST): we only require `code: string` to discriminate.\n * Provider, retriable, retryAfterMs, requestId are all optional — SDK error\n * paths may omit them (e.g., aborted before request, tool runtime error).\n */\ninterface AgentRunErrorLike {\n message: string\n code: string\n provider?: string\n retriable?: boolean\n retryAfterMs?: number\n requestId?: string\n /**\n * EC-15 (DOCUMENT) + invariant: `providerError` is QUARANTINED. We read it\n * for type-narrowing but NEVER serialize into the AgentEvent — leaking the\n * raw provider response could leak API keys, internal endpoints, or PII.\n * Only sanitized fields above flow to the SSE wire. `error.message` is\n * trusted to not contain secrets (SDK's responsibility per the v1.1.0\n * release contract).\n */\n providerError?: unknown\n}\n\n/**\n * EC-6 (SHOULD TEST): minimal type guard — only requires `code: string`.\n * Does NOT require `'provider' in err` because the SDK throws AgentRunErrors\n * without `provider` in local error paths (timeout, tool runtime error,\n * aborted-before-call).\n */\nfunction isAgentRunError(err: unknown): err is AgentRunErrorLike {\n if (!(err instanceof Error)) return false\n const e = err as { code?: unknown }\n return 'code' in e && typeof e.code === 'string'\n}\n\n/**\n * Map an SDK error to the AgentErrorEvent shape. Pure function — easy to test.\n *\n * Backward compat (D4): non-AgentRunError throws yield only `message` field\n * (legacy shape); discriminated fields stay `undefined`.\n *\n * Return type is the specific `AgentErrorEvent` (not the union) for ergonomic\n * call-site access — `errorToEvent(err).code` works without narrowing.\n */\nexport function errorToEvent(err: unknown, id?: string): AgentErrorEvent {\n if (isAgentRunError(err)) {\n const event: AgentErrorEvent = {\n type: 'error',\n message: err.message,\n code: err.code,\n }\n if (err.provider !== undefined) event.provider = err.provider\n if (err.retriable !== undefined) event.retriable = err.retriable\n if (err.retryAfterMs !== undefined) event.retryAfterMs = err.retryAfterMs\n if (id !== undefined) event.id = id\n return event\n }\n // Fallback for non-AgentRunError throws (plain Error, string, plain object with message)\n let message: string\n if (err instanceof Error) {\n message = err.message\n } else if (typeof err === 'string') {\n message = err\n } else if (err !== null && typeof err === 'object' && 'message' in err) {\n const candidate: unknown = (err as Record<string, unknown>).message\n // Plain object with `message: string` — common for SDK status:error payloads\n message = typeof candidate === 'string' ? candidate : '[object Object]'\n } else if (err === null || err === undefined) {\n message = String(err)\n } else {\n message = '[non-stringifiable error]'\n }\n const event: AgentErrorEvent = { type: 'error', message }\n if (id !== undefined) event.id = id\n return event\n}\n\nfunction yieldFromToolCall(msg: ToolCallLike): AgentEvent {\n if (msg.status === 'running') {\n return {\n type: 'tool_call',\n name: msg.name,\n args: safeArgs(msg.args),\n id: msg.call_id,\n }\n }\n if (msg.status === 'completed') {\n const data = typeof msg.result === 'string' ? msg.result : safeJsonStringify(msg.result)\n return {\n type: 'tool_result',\n name: msg.name,\n data,\n id: msg.call_id,\n }\n }\n // status === 'error' — exhaustive by type\n const message = typeof msg.result === 'string' ? msg.result : `Tool ${msg.name} failed`\n return { type: 'error', message, id: msg.call_id }\n}\n\nexport async function* streamAgentRun(\n run: AgentRunLike,\n): AsyncGenerator<AgentEvent, void, unknown> {\n for await (const msg of run.stream()) {\n if (isAssistant(msg)) {\n for (const block of msg.message.content) {\n if (block.type === 'text' && typeof block.text === 'string' && block.text.length > 0) {\n yield { type: 'message', content: block.text }\n }\n }\n } else if (isToolCall(msg)) {\n yield yieldFromToolCall(msg)\n }\n // SDK-internal variants (system, user, thinking, status, task,\n // request, object_delta) are intentionally not yielded.\n }\n\n const result = await run.wait()\n if (result.status === 'error' && result.error !== undefined) {\n yield errorToEvent(result.error)\n }\n}\n","/**\n * Item #5 — `createConversationHistory`\n *\n * Orchestrator that resolves a stable `agentId` from (explicit → session →\n * cookie → fresh UUID), then returns an `@theokit/sdk` `Agent` via\n * `Agent.getOrCreate(agentId, options)`. Conversation turns auto-persist in\n * `<cwd>/.theokit/agents/<agentId>/messages.jsonl` — SDK owns the storage\n * (ADR D1). `MemorySettings` (facts recall layer) is opt-in passthrough via\n * `options.memory` (ADR D2).\n *\n * Security: agentId from cookie/explicit is attacker-controlled. The SDK\n * uses it as a filesystem path component AND we serialize it into Set-Cookie.\n * EC-1 enforces a strict regex `^[a-zA-Z0-9_-]{1,128}$` at every entry point;\n * invalid values fall through (treated as \"missing\") rather than throw.\n */\n\nimport { tryResolveProvider } from './provider-resolver.js'\n\n// ──────────────────────────────────────────────────────────────────────────\n// Structural types — mirrors of SDK shapes we don't want to hard-import\n// (the SDK is an OPTIONAL peer per item #4's stance).\n// ──────────────────────────────────────────────────────────────────────────\n\n/**\n * Minimum surface of an SDK Agent that consumers care about post-creation.\n * Structural match — any object with `send` + `dispose` of compatible\n * shape works. `send` returns a `SdkRunLike` (a Run-shaped object) that\n * `streamAgentRun` can consume. Permissive `unknown` for now; consumers\n * who want stricter types can cast to the SDK's own types.\n *\n * **T5.2 (architecture-cleanup) — DP-7 decision: KEEP (Opt B).** The 5 duck-typed\n * mirrors below were flagged as \"over-engineered\" by the 2026-05-27 architecture\n * review. Decision: KEEP them because `@theokit/sdk` is `devDependency` (not\n * required at runtime for consumers that don't use agent features). Removing\n * the mirrors would force a hard runtime dep on the SDK, breaking consumers\n * who build TheoKit apps without the agent layer.\n *\n * @kept Defensive duck-type. Do NOT replace with direct SDK type imports unless\n * `@theokit/sdk` is promoted from devDependency to dependency. If promoting,\n * ALSO drop the mirrors (Opt A from the architecture-cleanup plan T5.2).\n */\nexport interface SdkRunLike {\n stream: () => AsyncIterable<{ type: string }>\n wait: () => Promise<{ status: 'finished' | 'error' | 'cancelled'; error?: { message: string } }>\n}\n\nexport interface SdkAgent {\n send: (message: string, options?: unknown) => Promise<SdkRunLike>\n dispose: () => Promise<void>\n}\n\n/**\n * Phase 2 — structural duck-type of `@theokit/sdk`'s `ConversationStorageAdapter`.\n *\n * D2 (decoupling): we mirror the SDK's shape locally rather than hard-import\n * the SDK type. This lets consumers pass any object matching the structural\n * contract (own implementation, SDK's `FileSystemConversationStorage`,\n * `InMemoryConversationStorage`, or a Postgres/Redis recipe).\n *\n * EC-5 (SHOULD TEST — sync drift detection): the SDK type MUST be assignable\n * to this interface AND vice-versa. A contract test asserts both directions.\n *\n * `unknown` for the message payload avoids coupling to the SDK's `SDKMessage`\n * shape. Real consumers cast at the call site if they need stricter types.\n */\nexport interface ConversationStorageLike {\n getMessages(conversationId: string): Promise<readonly unknown[]>\n appendMessage(conversationId: string, message: unknown): Promise<void>\n deleteConversation(conversationId: string): Promise<void>\n listConversationIds?(opts?: { limit?: number }): Promise<readonly string[] | undefined>\n dispose?(): Promise<void>\n}\n\n/**\n * Minimum surface of `AgentOptions` accepted by `Agent.getOrCreate`. Forward-\n * compatible: callers pass whatever the SDK supports (memory, tools, etc.).\n *\n * Phase 2 adds typed `conversationStorage` slot. The index signature still\n * passes everything else opaquely.\n */\nexport interface SdkAgentOptions {\n apiKey?: string\n model?: { id: string }\n tools?: readonly unknown[]\n memory?: Record<string, unknown>\n /**\n * Phase 2 (Production-Readiness #1) — pluggable conversation persistence.\n * Default (when omitted): SDK falls back to `FileSystemConversationStorage`.\n * Required for serverless / multi-host deploys.\n */\n conversationStorage?: ConversationStorageLike\n [key: string]: unknown\n}\n\ninterface SdkModule {\n Agent: {\n getOrCreate: (agentId: string, options: SdkAgentOptions) => Promise<SdkAgent>\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Public API\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface ConversationHistoryArgs {\n /** Request — for reading the conversation cookie. */\n request: Request | { headers?: { cookie?: string } | Headers }\n /**\n * Response-like surface that accepts a `Set-Cookie` header. The primitive\n * appends a Set-Cookie line when issuing a new conversation id. If absent,\n * the primitive still reads the existing cookie but cannot issue a new\n * one — useful for read-only contexts.\n */\n response?: { headers: Headers }\n /** Explicit override — wins over session/cookie/uuid (ADR D3 step 1). */\n agentId?: string\n /** Auth session containing a `conversationId` field — ADR D3 step 2. */\n session?: { conversationId?: string } | null\n /** SDK AgentOptions forwarded to Agent.getOrCreate. apiKey + model required. */\n options: SdkAgentOptions\n /** Cookie name override. Default: 'theo_conversation'. */\n cookieName?: string\n /** Cookie max-age in seconds. Default + min: 30 days. Non-positive coerced to default (EC-4). */\n cookieMaxAge?: number\n}\n\nexport interface ConversationHistoryResult {\n /** The SDK Agent, ready to receive `agent.send(message)`. */\n agent: SdkAgent\n /** The resolved conversation id (useful for logging / debugging). */\n conversationId: string\n /** True when the id was newly generated (no prior cookie / session). */\n isNew: boolean\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Test seam — allows unit tests to swap the SDK without dynamic import flake.\n// Underscore-prefixed: NOT part of the public contract.\n// ──────────────────────────────────────────────────────────────────────────\n\nlet sdkOverride: SdkModule | null | undefined = undefined\n\n/** @internal */\nexport function __setSdkForTests(sdk: SdkModule | null): void {\n sdkOverride = sdk\n}\n\n/** @internal */\nexport function __resetSdkForTests(): void {\n sdkOverride = undefined\n}\n\nasync function loadSdk(): Promise<SdkModule> {\n // EC-2 (edge case review — MUST FIX): the SDK is an optional peer; if the\n // consumer never installed it, `import('@theokit/sdk')` throws\n // ERR_MODULE_NOT_FOUND. Re-throw with an actionable message.\n if (sdkOverride === null) {\n throw new Error(\n 'createConversationHistory requires @theokit/sdk. Install: pnpm add @theokit/sdk',\n )\n }\n if (sdkOverride !== undefined) return sdkOverride\n try {\n // Use `createRequire` — Node's CJS-style require resolves against the\n // process's actual node_modules tree, bypassing Vite's SSR import-\n // analysis pipeline. The dynamic ESM `import()` path got intercepted\n // by Vite's `vite:import-analysis` plugin and failed to find the SDK\n // even when it was installed; createRequire goes straight to Node.\n //\n // The SDK ships dual ESM+CJS (per its tsup build), so `require` yields\n // the same module the ESM `import` would.\n const { createRequire } = await import('node:module')\n const requireFn = createRequire(import.meta.url)\n const spec = '@theokit/sdk'\n const mod = requireFn(spec) as unknown as SdkModule\n return mod\n } catch (cause) {\n throw new Error(\n 'createConversationHistory requires @theokit/sdk. Install: pnpm add @theokit/sdk',\n { cause },\n )\n }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Implementation\n// ──────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_COOKIE_NAME = 'theo_conversation'\nconst DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 30 // 30 days\n\n/**\n * EC-1 (edge case review — MUST FIX): the agentId becomes a filesystem path\n * component (`<cwd>/.theokit/agents/<agentId>/messages.jsonl`) inside the SDK\n * AND is serialized into a Set-Cookie header. The SDK does NOT validate the\n * char set. An attacker setting `Cookie: theo_conversation=../../../etc/passwd`\n * could trigger arbitrary-path writes; an `agentId` with CRLF would inject\n * HTTP headers. The same regex kills both attacks.\n */\nconst AGENT_ID_REGEX = /^[a-zA-Z0-9_-]{1,128}$/\n\nfunction isValidAgentId(s: string | undefined | null): s is string {\n return typeof s === 'string' && AGENT_ID_REGEX.test(s)\n}\n\n/**\n * Minimal RFC 6265 cookie parser. Returns the FIRST occurrence of `name`\n * (EC-5 — pins first-wins behavior).\n */\nfunction readCookieValue(\n request: ConversationHistoryArgs['request'],\n name: string,\n): string | undefined {\n let raw: string | undefined\n const h = request.headers\n if (h === undefined) return undefined\n if (typeof (h as Headers).get === 'function') {\n raw = (h as Headers).get('cookie') ?? undefined\n } else {\n raw = (h as { cookie?: string }).cookie\n }\n if (raw === undefined || raw.length === 0) return undefined\n const pairs = raw.split(/[;,]/)\n for (const pair of pairs) {\n const eq = pair.indexOf('=')\n if (eq < 0) continue\n const k = pair.slice(0, eq).trim()\n if (k === name) return pair.slice(eq + 1).trim()\n }\n return undefined\n}\n\ninterface SerializeCookieOptions {\n httpOnly?: boolean\n sameSite?: 'lax' | 'strict' | 'none'\n maxAge?: number\n path?: string\n}\n\nfunction serializeCookie(name: string, value: string, options: SerializeCookieOptions): string {\n const parts: string[] = [`${name}=${value}`]\n if (options.path !== undefined) parts.push(`Path=${options.path}`)\n if (options.maxAge !== undefined) parts.push(`Max-Age=${options.maxAge}`)\n if (options.sameSite !== undefined) {\n const v = options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)\n parts.push(`SameSite=${v}`)\n }\n if (options.httpOnly === true) parts.push('HttpOnly')\n return parts.join('; ')\n}\n\nexport async function createConversationHistory(\n args: ConversationHistoryArgs,\n): Promise<ConversationHistoryResult> {\n const cookieName = args.cookieName ?? DEFAULT_COOKIE_NAME\n // EC-4 (edge case review — SHOULD TEST): coerce non-positive to default.\n // The `??` operator alone would let `0` through, producing `Max-Age=0`\n // which means \"delete cookie immediately\" — almost certainly not intent.\n const rawMaxAge = args.cookieMaxAge\n const cookieMaxAge =\n typeof rawMaxAge === 'number' && rawMaxAge > 0 ? rawMaxAge : DEFAULT_COOKIE_MAX_AGE\n\n // 1. Resolve agentId per ADR D3 — sources are validated; invalid values\n // fall through (treated as \"missing\") rather than throw.\n let conversationId: string | undefined\n let isNew = false\n const cookieOnRequest = readCookieValue(args.request, cookieName)\n\n if (isValidAgentId(args.agentId)) {\n conversationId = args.agentId\n } else if (args.session !== null && args.session !== undefined) {\n const sId = args.session.conversationId\n if (isValidAgentId(sId)) conversationId = sId\n }\n if (conversationId === undefined && isValidAgentId(cookieOnRequest)) {\n conversationId = cookieOnRequest\n }\n\n if (conversationId === undefined) {\n conversationId = crypto.randomUUID()\n isNew = true\n }\n\n // Issue (or refresh) the cookie when:\n // 1. The id was newly generated (no source had it), OR\n // 2. The request's cookie does NOT match the resolved id (explicit\n // `agentId` override, session-derived id, etc.). Without this,\n // callers that pre-probe the id (e.g. to build agentId-scoped tools)\n // and pass it via `agentId` would never get a Set-Cookie even on\n // first visit. Net effect: every response with a `response` slot\n // ensures the browser ends up with a cookie that matches the\n // resolved id.\n const shouldIssueCookie = isNew || cookieOnRequest !== conversationId\n if (shouldIssueCookie && args.response !== undefined) {\n const cookie = serializeCookie(cookieName, conversationId, {\n httpOnly: true,\n sameSite: 'lax',\n maxAge: cookieMaxAge,\n path: '/',\n })\n args.response.headers.append('set-cookie', cookie)\n }\n\n // 2. Auto-resolve provider via Strategy pattern (FAANG-grade — zero\n // conditionals no consumer). If `options.apiKey` ausente, lê env vars\n // priorizadas (OPENROUTER > OPENAI > ANTHROPIC) e injeta apiKey +\n // providers.baseUrl. Consumer override: passar `options.apiKey` explícito\n // SOBREPÕE o auto-resolve (escape hatch). Ver `provider-resolver.ts` +\n // Dapr Conversation Registry pattern (`referencias/dapr/pkg/components/conversation/`).\n const resolvedOptions = autoResolveProviderIfNeeded(args.options)\n\n // 3. Resolve the agent via SDK.\n const sdk = await loadSdk()\n const agent = await sdk.Agent.getOrCreate(conversationId, resolvedOptions)\n\n return { agent, conversationId, isNew }\n}\n\n/**\n * Auto-inject provider config (apiKey + baseUrl) via Strategy pattern when\n * consumer didn't pass apiKey explicit. Idempotent — se apiKey já set, noop.\n *\n * Output shape:\n * {\n * ...originalOptions,\n * apiKey: env, // resolved from process.env\n * providers: { routes: [{ capability: 'chat', provider: name, ... }] }\n * }\n */\nfunction autoResolveProviderIfNeeded(options: SdkAgentOptions): SdkAgentOptions {\n // Escape hatch — consumer override wins.\n if (typeof options.apiKey === 'string' && options.apiKey.length > 0) {\n return options\n }\n // Auto-resolve via Strategy registry.\n //\n // Finding A workaround (sdk-residual-behavior-2026-05-28): SDK silently\n // returns canned \"Hello! How can I assist you today?\" content when no\n // apiKey AND no provider env vars are present. Fail-fast HERE with an\n // actionable error — template's try/catch yields `{type:'error'}` SSE\n // event so consumer sees what's wrong.\n const resolved = tryResolveProvider()\n if (resolved === null) {\n throw new Error(\n 'No LLM provider API key found in environment. ' +\n 'Set OPENROUTER_API_KEY (recommended — gateway to many models) OR ' +\n 'OPENAI_API_KEY OR ANTHROPIC_API_KEY in your .env. ' +\n 'Get a free OpenRouter key at https://openrouter.ai/keys. ' +\n '(Pass `options.apiKey` explicitly to bypass auto-resolution.)',\n )\n }\n // Inject apiKey + provider routing. SDK ProviderRoutingSettings shape.\n // Note: we use `chat` capability since this is the conversation primitive;\n // SDK may extend to embeddings/etc — those routes are separate concerns.\n return {\n ...options,\n apiKey: resolved.apiKey,\n providers: {\n routes: [{ capability: 'chat', provider: resolved.name, baseUrl: resolved.baseUrl }],\n },\n }\n}\n"],"mappings":"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","names":["event"]}
|
package/dist/chunk-EXP56GFQ.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// src/server/agent/provider-resolver.ts
|
|
2
|
-
var DEFAULT_REGISTRY = [
|
|
3
|
-
{
|
|
4
|
-
name: "openrouter",
|
|
5
|
-
envKey: "OPENROUTER_API_KEY",
|
|
6
|
-
baseUrl: "https://openrouter.ai/api/v1",
|
|
7
|
-
priority: 1
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
name: "openai",
|
|
11
|
-
envKey: "OPENAI_API_KEY",
|
|
12
|
-
baseUrl: "https://api.openai.com/v1",
|
|
13
|
-
priority: 2
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: "anthropic",
|
|
17
|
-
envKey: "ANTHROPIC_API_KEY",
|
|
18
|
-
baseUrl: "https://api.anthropic.com",
|
|
19
|
-
priority: 3
|
|
20
|
-
}
|
|
21
|
-
];
|
|
22
|
-
var registry = [...DEFAULT_REGISTRY];
|
|
23
|
-
function resolveProvider() {
|
|
24
|
-
const sorted = [...registry].sort((a, b) => a.priority - b.priority);
|
|
25
|
-
for (const desc of sorted) {
|
|
26
|
-
const apiKey = process.env[desc.envKey];
|
|
27
|
-
if (apiKey && apiKey.length > 0) {
|
|
28
|
-
return {
|
|
29
|
-
name: desc.name,
|
|
30
|
-
apiKey,
|
|
31
|
-
baseUrl: desc.baseUrl
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const envKeys = sorted.map((p) => p.envKey).join(" OR ");
|
|
36
|
-
throw new Error(
|
|
37
|
-
`No LLM provider API key found in environment. Set one of: ${envKeys}. Get a free OpenRouter key at https://openrouter.ai/keys (recommended \u2014 one key, many models).`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
function tryResolveProvider() {
|
|
41
|
-
try {
|
|
42
|
-
return resolveProvider();
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export {
|
|
49
|
-
resolveProvider,
|
|
50
|
-
tryResolveProvider
|
|
51
|
-
};
|
|
52
|
-
//# sourceMappingURL=chunk-EXP56GFQ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/agent/provider-resolver.ts"],"sourcesContent":["/**\n * Provider Resolver — Strategy + Registry pattern (FAANG-grade).\n *\n * Inspiração: Dapr Conversation Registry (`dapr/pkg/components/conversation/registry.go`)\n * + Encore Manager provider array (`encore/runtimes/go/pubsub/manager_internal.go`).\n *\n * Princípio: provider routing é responsabilidade do FRAMEWORK, não do consumer.\n * Consumer template usa `model: { id: 'gpt-4o-mini' }` puro — sem conditionals.\n *\n * Wire protocol: OpenAI Chat Completions (universal — implementado por todos\n * os providers: OpenRouter, Groq, Mistral, Together, Anthropic via proxy, etc).\n *\n * Resolução por prioridade (FIRST match wins):\n * 1. OPENROUTER_API_KEY → baseUrl=openrouter.ai (gateway multi-modelo)\n * 2. OPENAI_API_KEY → baseUrl=api.openai.com\n * 3. ANTHROPIC_API_KEY → direct Anthropic (Messages API, não OpenAI-compat)\n *\n * Escape hatch: `options.apiKey` explícito SOBREPÕE auto-resolution\n * (consumer pode forçar provider específico se quiser).\n */\n\n/**\n * Provider configuration descriptor — Registry entry shape.\n *\n * @public\n */\nexport interface ProviderDescriptor {\n /** Stable name used internally — não exposto no wire. */\n name: string\n /** Environment variable that holds the API key for this provider. */\n envKey: string\n /** Base URL for the provider's OpenAI-compatible (or native) API. */\n baseUrl: string\n /** Resolution priority (lower = higher priority). FIRST match wins. */\n priority: number\n}\n\n/**\n * Resolved provider configuration — output of `resolveProvider()`.\n *\n * @public\n */\nexport interface ResolvedProvider {\n name: string\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Default provider registry. Order = priority (first = highest).\n *\n * Adding a new provider:\n * 1. Append entry below (or register via `registerProvider()`).\n * 2. Set `envKey` matching the user's env var convention.\n * 3. Set `baseUrl` to the OpenAI-compat endpoint (or native if not compat).\n * 4. Provider name used in telemetry/logs only — never wire-exposed.\n */\nconst DEFAULT_REGISTRY: ProviderDescriptor[] = [\n {\n name: 'openrouter',\n envKey: 'OPENROUTER_API_KEY',\n baseUrl: 'https://openrouter.ai/api/v1',\n priority: 1,\n },\n {\n name: 'openai',\n envKey: 'OPENAI_API_KEY',\n baseUrl: 'https://api.openai.com/v1',\n priority: 2,\n },\n {\n name: 'anthropic',\n envKey: 'ANTHROPIC_API_KEY',\n baseUrl: 'https://api.anthropic.com',\n priority: 3,\n },\n]\n\n/**\n * Runtime registry — copy of DEFAULT_REGISTRY mutable via registerProvider().\n * Sorted by priority on every resolve (stable, O(n log n) — n <= ~10 providers).\n */\nconst registry: ProviderDescriptor[] = [...DEFAULT_REGISTRY]\n\n/**\n * Register a new provider (Registry pattern — runtime extension point).\n * Useful for self-hosted endpoints or custom providers without touching theokit src.\n *\n * @example\n * registerProvider({\n * name: 'self-hosted',\n * envKey: 'SELF_HOSTED_API_KEY',\n * baseUrl: 'https://llm.internal.acme.com/v1',\n * priority: 0, // highest priority\n * })\n *\n * @public\n */\nexport function registerProvider(descriptor: ProviderDescriptor): void {\n // Idempotent — replace existing by name.\n const idx = registry.findIndex((p) => p.name === descriptor.name)\n if (idx >= 0) registry[idx] = descriptor\n else registry.push(descriptor)\n}\n\n/**\n * Reset registry to DEFAULT_REGISTRY (test-only / dev escape hatch).\n *\n * @public\n */\nexport function resetProviderRegistry(): void {\n registry.length = 0\n registry.push(...DEFAULT_REGISTRY)\n}\n\n/**\n * Get current registry snapshot (read-only — inspection).\n *\n * @public\n */\nexport function listProviders(): readonly ProviderDescriptor[] {\n return [...registry].sort((a, b) => a.priority - b.priority)\n}\n\n/**\n * Resolve provider from env vars by priority. FIRST env var found wins.\n *\n * @returns ResolvedProvider with apiKey + baseUrl + name\n * @throws Error if NO provider env var is set (actionable message)\n *\n * @public\n */\nexport function resolveProvider(): ResolvedProvider {\n const sorted = [...registry].sort((a, b) => a.priority - b.priority)\n for (const desc of sorted) {\n const apiKey = process.env[desc.envKey]\n if (apiKey && apiKey.length > 0) {\n return {\n name: desc.name,\n apiKey,\n baseUrl: desc.baseUrl,\n }\n }\n }\n // No env var found — emit actionable error.\n const envKeys = sorted.map((p) => p.envKey).join(' OR ')\n throw new Error(\n `No LLM provider API key found in environment. Set one of: ${envKeys}. ` +\n `Get a free OpenRouter key at https://openrouter.ai/keys (recommended — one key, many models).`,\n )\n}\n\n/**\n * Try to resolve — does NOT throw. Returns null if no provider available.\n * Useful for graceful degradation (e.g., mock mode).\n *\n * @public\n */\nexport function tryResolveProvider(): ResolvedProvider | null {\n try {\n return resolveProvider()\n } catch {\n return null\n }\n}\n"],"mappings":";AAyDA,IAAM,mBAAyC;AAAA,EAC7C;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AACF;AAMA,IAAM,WAAiC,CAAC,GAAG,gBAAgB;AAkDpD,SAAS,kBAAoC;AAClD,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AACnE,aAAW,QAAQ,QAAQ;AACzB,UAAM,SAAS,QAAQ,IAAI,KAAK,MAAM;AACtC,QAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX;AAAA,QACA,SAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM;AACvD,QAAM,IAAI;AAAA,IACR,6DAA6D,OAAO;AAAA,EAEtE;AACF;AAQO,SAAS,qBAA8C;AAC5D,MAAI;AACF,WAAO,gBAAgB;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/define/ui-message-stream-response.ts"],"sourcesContent":["import type { UIMessageChunk } from 'ai'\n\n/**\n * M0 (theokit-ai-first) — serialize a stream of ai-sdk `UIMessageChunk`s into a\n * Web-Standards `Response` on the UIMessageStream wire so `@ai-sdk/react`'s\n * `useChat` consumes it WITHOUT a custom adapter.\n *\n * Wire contract (must match ai-sdk's consumer transport exactly):\n * - `content-type: text/event-stream`\n * - `x-vercel-ai-ui-message-stream: v1` — the version marker `useChat` checks\n * - each chunk framed as `data: ${JSON.stringify(chunk)}\\n\\n`\n * - a terminal `data: [DONE]\\n\\n` after the last chunk (ignored by the parser)\n *\n * Web Standards only — `Response` + `ReadableStream` (G8, no node:http). The\n * headers commit before the stream starts (mirrors define-agent-endpoint.ts).\n *\n * Fail-clear (error-handling.md): if the source iterable throws mid-stream, the\n * `[DONE]` terminal is still flushed and the stream is closed — never left\n * hanging. (The translator upstream already closes gracefully; this is defense\n * in depth for any other chunk source.)\n */\nconst UI_MESSAGE_STREAM_HEADERS = {\n 'content-type': 'text/event-stream',\n 'x-vercel-ai-ui-message-stream': 'v1',\n} as const\n\nconst DONE_FRAME = 'data: [DONE]\\n\\n'\n\nfunction encode(text: string): Uint8Array {\n return new TextEncoder().encode(text)\n}\n\nexport function uiMessageStreamResponse(chunks: AsyncIterable<UIMessageChunk>): Response {\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n for await (const chunk of chunks) {\n controller.enqueue(encode(`data: ${JSON.stringify(chunk)}\\n\\n`))\n }\n } catch {\n // The source iterable aborted mid-stream. The upstream translator owns\n // error semantics (it surfaces failures as chunks + closes gracefully);\n // this transport's sole guarantee is a terminated stream — fall through\n // to the DONE terminal rather than re-throw and error an open stream.\n } finally {\n controller.enqueue(encode(DONE_FRAME))\n controller.close()\n }\n },\n })\n return new Response(stream, { headers: UI_MESSAGE_STREAM_HEADERS })\n}\n"],"mappings":";AAqBA,IAAM,4BAA4B;AAAA,EAChC,gBAAgB;AAAA,EAChB,iCAAiC;AACnC;AAEA,IAAM,aAAa;AAEnB,SAAS,OAAO,MAA0B;AACxC,SAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AACtC;AAEO,SAAS,wBAAwB,QAAiD;AACvF,QAAM,SAAS,IAAI,eAA2B;AAAA,IAC5C,MAAM,MAAM,YAAY;AACtB,UAAI;AACF,yBAAiB,SAAS,QAAQ;AAChC,qBAAW,QAAQ,OAAO,SAAS,KAAK,UAAU,KAAK,CAAC;AAAA;AAAA,CAAM,CAAC;AAAA,QACjE;AAAA,MACF,QAAQ;AAAA,MAKR,UAAE;AACA,mBAAW,QAAQ,OAAO,UAAU,CAAC;AACrC,mBAAW,MAAM;AAAA,MACnB;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,IAAI,SAAS,QAAQ,EAAE,SAAS,0BAA0B,CAAC;AACpE;","names":[]}
|