agentic-kit 1.3.1 โ†’ 1.4.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/LICENSE CHANGED
@@ -1,7 +1,8 @@
1
- MIT License
1
+ The MIT License (MIT)
2
2
 
3
3
  Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
4
  Copyright (c) 2025 Constructive <developers@constructive.io>
5
+ Copyright (c) 2020-present, Interweb, Inc.
5
6
 
6
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
8
  of this software and associated documentation files (the "Software"), to deal
@@ -19,4 +20,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
20
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
21
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
22
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- SOFTWARE.
23
+ SOFTWARE.
package/README.md CHANGED
@@ -121,11 +121,30 @@ Use `createOpenAIKit`, `createAnthropicKit`, `createOllamaKit`, or
121
121
 
122
122
  ---
123
123
 
124
- ## Related Constructive Tooling
124
+ ## Education and Tutorials
125
+
126
+ 1. ๐Ÿš€ [Quickstart: Getting Up and Running](https://constructive.io/learn/quickstart)
127
+ Get started with modular databases in minutes. Install prerequisites and deploy your first module.
128
+
129
+ 2. ๐Ÿ“ฆ [Modular PostgreSQL Development with Database Packages](https://constructive.io/learn/modular-postgres)
130
+ Learn to organize PostgreSQL projects with pgpm workspaces and reusable database modules.
131
+
132
+ 3. โœ๏ธ [Authoring Database Changes](https://constructive.io/learn/authoring-database-changes)
133
+ Master the workflow for adding, organizing, and managing database changes with pgpm.
125
134
 
126
- ### ๐Ÿค– AI & Agent Development
135
+ 4. ๐Ÿงช [End-to-End PostgreSQL Testing with TypeScript](https://constructive.io/learn/e2e-postgres-testing)
136
+ Master end-to-end PostgreSQL testing with ephemeral databases, RLS testing, and CI/CD automation.
127
137
 
128
- * [agentic-kit](https://github.com/constructive-io/agentic-kit): **๐Ÿงฐ Provider-agnostic LLM adapter** with streaming and multi-turn support. Swap between Anthropic, OpenAI, Ollama, and any OpenAI-compatible endpoint.
138
+ 5. โšก [Supabase Testing](https://constructive.io/learn/supabase)
139
+ Use TypeScript-first tools to test Supabase projects with realistic RLS, policies, and auth contexts.
140
+
141
+ 6. ๐Ÿ’ง [Drizzle ORM Testing](https://constructive.io/learn/drizzle-testing)
142
+ Run full-stack tests with Drizzle ORM, including database setup, teardown, and RLS enforcement.
143
+
144
+ 7. ๐Ÿ”ง [Troubleshooting](https://constructive.io/learn/troubleshooting)
145
+ Common issues and solutions for pgpm, PostgreSQL, and testing.
146
+
147
+ ## Related Constructive Tooling
129
148
 
130
149
  ### ๐Ÿ“ฆ Package Management
131
150
 
@@ -136,14 +155,33 @@ Use `createOpenAIKit`, `createAnthropicKit`, `createOllamaKit`, or
136
155
  * [pgsql-test](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-test): **๐Ÿ“Š Isolated testing environments** with per-test transaction rollbacksโ€”ideal for integration tests, complex migrations, and RLS simulation.
137
156
  * [pgsql-seed](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-seed): **๐ŸŒฑ PostgreSQL seeding utilities** for CSV, JSON, SQL data loading, and pgpm deployment.
138
157
  * [supabase-test](https://github.com/constructive-io/constructive/tree/main/postgres/supabase-test): **๐Ÿงช Supabase-native test harness** preconfigured for the local Supabase stackโ€”per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
158
+ * [graphile-test](https://github.com/constructive-io/constructive/tree/main/graphile/graphile-test): **๐Ÿ” Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
159
+ * [pg-query-context](https://github.com/constructive-io/constructive/tree/main/postgres/pg-query-context): **๐Ÿ”’ Session context injection** to add session-local context (e.g., `SET LOCAL`) into queriesโ€”ideal for setting `role`, `jwt.claims`, and other session settings.
139
160
 
140
161
  ### ๐Ÿง  Parsing & AST
141
162
 
142
163
  * [pgsql-parser](https://www.npmjs.com/package/pgsql-parser): **๐Ÿ”„ SQL conversion engine** that interprets and converts PostgreSQL syntax.
143
164
  * [libpg-query-node](https://www.npmjs.com/package/libpg-query): **๐ŸŒ‰ Node.js bindings** for `libpg_query`, converting SQL into parse trees.
165
+ * [pg-proto-parser](https://www.npmjs.com/package/pg-proto-parser): **๐Ÿ“ฆ Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
166
+ * [@pgsql/enums](https://www.npmjs.com/package/@pgsql/enums): **๐Ÿท๏ธ TypeScript enums** for PostgreSQL AST for safe and ergonomic parsing logic.
144
167
  * [@pgsql/types](https://www.npmjs.com/package/@pgsql/types): **๐Ÿ“ Type definitions** for PostgreSQL AST nodes in TypeScript.
145
168
  * [@pgsql/utils](https://www.npmjs.com/package/@pgsql/utils): **๐Ÿ› ๏ธ AST utilities** for constructing and transforming PostgreSQL syntax trees.
146
169
 
170
+ ### ๐Ÿ“š Documentation & Skills
171
+
172
+ * [constructive-skills](https://github.com/constructive-io/constructive-skills): **๐Ÿ“– Platform documentation and AI agent skills** โ€” feature catalog, blueprint reference, SDK guides (i18n, billing, limits, events, uploads, security, entities, search, AI), and deployment guides.
173
+
174
+ Install skills for AI coding agents:
175
+
176
+ ```bash
177
+ # All platform skills (security, blueprints, codegen, billing, etc.)
178
+ npx skills add constructive-io/constructive-skills
179
+
180
+ # Individual repo skills (pgpm, testing, CLI, search, etc.)
181
+ npx skills add https://github.com/constructive-io/constructive --skill pgpm
182
+ npx skills add https://github.com/constructive-io/constructive --skill constructive-testing
183
+ ```
184
+
147
185
  ## Credits
148
186
 
149
187
  **๐Ÿ›  Built by the [Constructive](https://constructive.io) team โ€” creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).**
package/esm/index.js CHANGED
@@ -1,15 +1,12 @@
1
1
  import { ANTHROPIC_MODELS, AnthropicAdapter } from '@agentic-kit/anthropic';
2
2
  import { OLLAMA_MODELS, OllamaAdapter, OllamaClient } from '@agentic-kit/ollama';
3
3
  import { OPENAI_COMPATIBLE_MODELS, OpenAIAdapter, } from '@agentic-kit/openai';
4
- import { createAssistantMessageEventStream, EventStream } from './event-stream.js';
5
- import { createEmptyUsage, getMessageText, normalizeContext } from './messages.js';
4
+ import { createAssistantMessageEventStream, createEmptyUsage, EventStream, getMessageText, normalizeContext, } from '@agentic-kit/protocol';
6
5
  import { clearModels, getModel, getModels, getProviders as getModelProviders, registerModel, registerModels, } from './model-registry.js';
7
6
  import { clearProviders, getProvider as getRegisteredProvider, getProviders as getRegisteredProviders, registerProvider, unregisterProviders, } from './provider-registry.js';
8
7
  import { transformMessages } from './transform-messages.js';
9
- export * from './event-stream.js';
10
- export * from './messages.js';
11
8
  export * from './transform-messages.js';
12
- export * from './types.js';
9
+ export * from '@agentic-kit/protocol';
13
10
  export { createAssistantMessageEventStream, EventStream, OllamaClient };
14
11
  export { AnthropicAdapter, OllamaAdapter, OpenAIAdapter };
15
12
  registerModels([...OPENAI_COMPATIBLE_MODELS, ...ANTHROPIC_MODELS, ...OLLAMA_MODELS]);
package/index.d.ts CHANGED
@@ -1,14 +1,11 @@
1
1
  import { AnthropicAdapter, type AnthropicOptions } from '@agentic-kit/anthropic';
2
2
  import { OllamaAdapter, OllamaClient } from '@agentic-kit/ollama';
3
3
  import { OpenAIAdapter, type OpenAIOptions } from '@agentic-kit/openai';
4
- import { createAssistantMessageEventStream, EventStream } from './event-stream.js';
4
+ import { type AssistantMessage, type AssistantMessageEventStream, type Context, createAssistantMessageEventStream, EventStream, type LegacyChatMessage, type LegacyGenerateInput, type LegacyStreamingOptions, type ModelDescriptor, type ProviderAdapter, type StreamOptions } from '@agentic-kit/protocol';
5
5
  import { clearModels, getModel, getModels, getProviders as getModelProviders, registerModel, registerModels } from './model-registry.js';
6
6
  import { clearProviders, getProvider as getRegisteredProvider, getProviders as getRegisteredProviders, registerProvider, unregisterProviders } from './provider-registry.js';
7
- import type { AssistantMessage, AssistantMessageEventStream, Context, LegacyChatMessage, LegacyGenerateInput, LegacyStreamingOptions, ModelDescriptor, ProviderAdapter, StreamOptions } from './types.js';
8
- export * from './event-stream.js';
9
- export * from './messages.js';
10
7
  export * from './transform-messages.js';
11
- export * from './types.js';
8
+ export * from '@agentic-kit/protocol';
12
9
  export { createAssistantMessageEventStream, EventStream, OllamaClient };
13
10
  export { AnthropicAdapter, OllamaAdapter, OpenAIAdapter };
14
11
  export type { AnthropicOptions, OpenAIOptions };
package/index.js CHANGED
@@ -29,10 +29,9 @@ Object.defineProperty(exports, "OllamaAdapter", { enumerable: true, get: functio
29
29
  Object.defineProperty(exports, "OllamaClient", { enumerable: true, get: function () { return ollama_1.OllamaClient; } });
30
30
  const openai_1 = require("@agentic-kit/openai");
31
31
  Object.defineProperty(exports, "OpenAIAdapter", { enumerable: true, get: function () { return openai_1.OpenAIAdapter; } });
32
- const event_stream_js_1 = require("./event-stream.js");
33
- Object.defineProperty(exports, "createAssistantMessageEventStream", { enumerable: true, get: function () { return event_stream_js_1.createAssistantMessageEventStream; } });
34
- Object.defineProperty(exports, "EventStream", { enumerable: true, get: function () { return event_stream_js_1.EventStream; } });
35
- const messages_js_1 = require("./messages.js");
32
+ const protocol_1 = require("@agentic-kit/protocol");
33
+ Object.defineProperty(exports, "createAssistantMessageEventStream", { enumerable: true, get: function () { return protocol_1.createAssistantMessageEventStream; } });
34
+ Object.defineProperty(exports, "EventStream", { enumerable: true, get: function () { return protocol_1.EventStream; } });
36
35
  const model_registry_js_1 = require("./model-registry.js");
37
36
  Object.defineProperty(exports, "clearModels", { enumerable: true, get: function () { return model_registry_js_1.clearModels; } });
38
37
  Object.defineProperty(exports, "getModel", { enumerable: true, get: function () { return model_registry_js_1.getModel; } });
@@ -47,10 +46,8 @@ Object.defineProperty(exports, "getRegisteredProviders", { enumerable: true, get
47
46
  Object.defineProperty(exports, "registerProvider", { enumerable: true, get: function () { return provider_registry_js_1.registerProvider; } });
48
47
  Object.defineProperty(exports, "unregisterProviders", { enumerable: true, get: function () { return provider_registry_js_1.unregisterProviders; } });
49
48
  const transform_messages_js_1 = require("./transform-messages.js");
50
- __exportStar(require("./event-stream.js"), exports);
51
- __exportStar(require("./messages.js"), exports);
52
49
  __exportStar(require("./transform-messages.js"), exports);
53
- __exportStar(require("./types.js"), exports);
50
+ __exportStar(require("@agentic-kit/protocol"), exports);
54
51
  (0, model_registry_js_1.registerModels)([...openai_1.OPENAI_COMPATIBLE_MODELS, ...anthropic_1.ANTHROPIC_MODELS, ...ollama_1.OLLAMA_MODELS]);
55
52
  (0, provider_registry_js_1.registerProvider)(new openai_1.OpenAIAdapter());
56
53
  (0, provider_registry_js_1.registerProvider)(new anthropic_1.AnthropicAdapter({ apiKey: '' }));
@@ -68,7 +65,7 @@ async function complete(model, context, options) {
68
65
  }
69
66
  async function completeText(model, context, options) {
70
67
  const message = await complete(model, context, options);
71
- return (0, messages_js_1.getMessageText)(message);
68
+ return (0, protocol_1.getMessageText)(message);
72
69
  }
73
70
  class AgentKit {
74
71
  providers = new Map();
@@ -126,7 +123,7 @@ class AgentKit {
126
123
  try {
127
124
  const message = assertLegacyGenerateSucceeded(await completeWithProvider(provider, model, context, streamOptions));
128
125
  options?.onStateChange?.('complete');
129
- const text = (0, messages_js_1.getMessageText)(message);
126
+ const text = (0, protocol_1.getMessageText)(message);
130
127
  options?.onComplete?.();
131
128
  return text;
132
129
  }
@@ -167,7 +164,7 @@ function legacyInputToContext(input) {
167
164
  provider: 'legacy',
168
165
  model: input.model,
169
166
  content: [{ type: 'text', text: message.content }],
170
- usage: (0, messages_js_1.createEmptyUsage)(),
167
+ usage: (0, protocol_1.createEmptyUsage)(),
171
168
  stopReason: 'stop',
172
169
  timestamp: Date.now(),
173
170
  }
@@ -202,7 +199,7 @@ function createLegacyModel(provider, modelId, maxTokens) {
202
199
  };
203
200
  }
204
201
  function streamWithProvider(provider, model, context, options) {
205
- const normalized = (0, messages_js_1.normalizeContext)(context);
202
+ const normalized = (0, protocol_1.normalizeContext)(context);
206
203
  const transformedContext = {
207
204
  ...normalized,
208
205
  messages: (0, transform_messages_js_1.transformMessages)(normalized.messages, model),
@@ -1,4 +1,4 @@
1
- import type { ModelDescriptor } from './types.js';
1
+ import type { ModelDescriptor } from '@agentic-kit/protocol';
2
2
  export declare function registerModel(model: ModelDescriptor): void;
3
3
  export declare function registerModels(models: ModelDescriptor[]): void;
4
4
  export declare function getModel(provider: string, modelId: string): ModelDescriptor | undefined;
package/package.json CHANGED
@@ -1,19 +1,12 @@
1
1
  {
2
2
  "name": "agentic-kit",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "author": "Dan Lynch <pyramation@gmail.com>",
5
5
  "description": "Provider-agnostic LLM adapter with streaming and multi-turn support",
6
6
  "main": "index.js",
7
7
  "module": "esm/index.js",
8
8
  "types": "index.d.ts",
9
- "exports": {
10
- ".": {
11
- "types": "./index.d.ts",
12
- "import": "./esm/index.js",
13
- "require": "./index.js"
14
- }
15
- },
16
- "homepage": "https://github.com/constructive-io/agentic-kit",
9
+ "homepage": "https://github.com/constructive-io/constructive",
17
10
  "license": "SEE LICENSE IN LICENSE",
18
11
  "publishConfig": {
19
12
  "access": "public",
@@ -21,26 +14,26 @@
21
14
  },
22
15
  "repository": {
23
16
  "type": "git",
24
- "url": "https://github.com/constructive-io/agentic-kit"
17
+ "url": "https://github.com/constructive-io/constructive"
25
18
  },
26
19
  "bugs": {
27
- "url": "https://github.com/constructive-io/agentic-kit/issues"
20
+ "url": "https://github.com/constructive-io/constructive/issues"
28
21
  },
29
22
  "scripts": {
30
23
  "clean": "makage clean",
31
24
  "prepack": "npm run build",
32
25
  "build": "makage build",
33
- "postbuild": "node ../../scripts/write-esm-package-json.js",
34
26
  "build:dev": "makage build --dev",
35
27
  "lint": "eslint . --fix",
36
28
  "test": "jest",
37
29
  "test:watch": "jest --watch"
38
30
  },
39
31
  "dependencies": {
40
- "@agentic-kit/anthropic": "1.2.1",
41
- "@agentic-kit/ollama": "2.0.0",
42
- "@agentic-kit/openai": "1.2.1"
32
+ "@agentic-kit/anthropic": "1.3.0",
33
+ "@agentic-kit/ollama": "2.1.0",
34
+ "@agentic-kit/openai": "1.3.0",
35
+ "@agentic-kit/protocol": "1.2.0"
43
36
  },
44
37
  "keywords": [],
45
- "gitHead": "c2b13e65b26f14c9983e9b7cc4eafbe4919b13d4"
38
+ "gitHead": "fc6f9780ea1cab2c9344c2e392649ae644e84849"
46
39
  }
@@ -1,4 +1,4 @@
1
- import type { ProviderAdapter } from './types.js';
1
+ import type { ProviderAdapter } from '@agentic-kit/protocol';
2
2
  export declare function registerProvider(adapter: ProviderAdapter, sourceId?: string): void;
3
3
  export declare function getProvider(api: string): ProviderAdapter | undefined;
4
4
  export declare function getProviders(): ProviderAdapter[];
@@ -1,2 +1,2 @@
1
- import type { Message, ModelDescriptor } from './types.js';
1
+ import type { Message, ModelDescriptor } from '@agentic-kit/protocol';
2
2
  export declare function transformMessages(messages: Message[], model: ModelDescriptor): Message[];
@@ -1,77 +0,0 @@
1
- export class EventStream {
2
- isTerminal;
3
- extractResult;
4
- queue = [];
5
- waiting = [];
6
- done = false;
7
- finalResultPromise;
8
- resolveFinalResult;
9
- constructor(isTerminal, extractResult) {
10
- this.isTerminal = isTerminal;
11
- this.extractResult = extractResult;
12
- this.finalResultPromise = new Promise((resolve) => {
13
- this.resolveFinalResult = resolve;
14
- });
15
- }
16
- push(event) {
17
- if (this.done) {
18
- return;
19
- }
20
- if (this.isTerminal(event)) {
21
- this.done = true;
22
- this.resolveFinalResult(this.extractResult(event));
23
- }
24
- const waiter = this.waiting.shift();
25
- if (waiter) {
26
- waiter({ value: event, done: false });
27
- return;
28
- }
29
- this.queue.push(event);
30
- }
31
- end(result) {
32
- this.done = true;
33
- if (result !== undefined) {
34
- this.resolveFinalResult(result);
35
- }
36
- while (this.waiting.length > 0) {
37
- this.waiting.shift()({ value: undefined, done: true });
38
- }
39
- }
40
- async *[Symbol.asyncIterator]() {
41
- while (true) {
42
- if (this.queue.length > 0) {
43
- yield this.queue.shift();
44
- continue;
45
- }
46
- if (this.done) {
47
- return;
48
- }
49
- const next = await new Promise((resolve) => {
50
- this.waiting.push(resolve);
51
- });
52
- if (next.done) {
53
- return;
54
- }
55
- yield next.value;
56
- }
57
- }
58
- result() {
59
- return this.finalResultPromise;
60
- }
61
- }
62
- export class DefaultAssistantMessageEventStream extends EventStream {
63
- constructor() {
64
- super((event) => event.type === 'done' || event.type === 'error', (event) => {
65
- if (event.type === 'done') {
66
- return event.message;
67
- }
68
- if (event.type === 'error') {
69
- return event.error;
70
- }
71
- throw new Error('Unexpected terminal event');
72
- });
73
- }
74
- }
75
- export function createAssistantMessageEventStream() {
76
- return new DefaultAssistantMessageEventStream();
77
- }
package/esm/messages.js DELETED
@@ -1,147 +0,0 @@
1
- export function createEmptyUsage() {
2
- return {
3
- input: 0,
4
- output: 0,
5
- reasoning: 0,
6
- cacheRead: 0,
7
- cacheWrite: 0,
8
- totalTokens: 0,
9
- cost: {
10
- input: 0,
11
- output: 0,
12
- cacheRead: 0,
13
- cacheWrite: 0,
14
- total: 0,
15
- },
16
- };
17
- }
18
- export function calculateUsageCost(model, usage) {
19
- const schedule = model.cost;
20
- usage.cost.input = ((schedule?.input ?? 0) / 1_000_000) * usage.input;
21
- usage.cost.output = ((schedule?.output ?? 0) / 1_000_000) * usage.output;
22
- usage.cost.cacheRead = ((schedule?.cacheRead ?? 0) / 1_000_000) * usage.cacheRead;
23
- usage.cost.cacheWrite = ((schedule?.cacheWrite ?? 0) / 1_000_000) * usage.cacheWrite;
24
- usage.cost.total =
25
- usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
26
- }
27
- export function snapshotUsage(usage) {
28
- return { ...usage, cost: { ...usage.cost } };
29
- }
30
- export function addUsage(target, delta) {
31
- target.input += delta.input;
32
- target.output += delta.output;
33
- target.reasoning += delta.reasoning;
34
- target.cacheRead += delta.cacheRead;
35
- target.cacheWrite += delta.cacheWrite;
36
- target.totalTokens += delta.totalTokens;
37
- target.cost.input += delta.cost.input;
38
- target.cost.output += delta.cost.output;
39
- target.cost.cacheRead += delta.cost.cacheRead;
40
- target.cost.cacheWrite += delta.cost.cacheWrite;
41
- target.cost.total += delta.cost.total;
42
- return target;
43
- }
44
- export function createAssistantMessage(model) {
45
- return {
46
- role: 'assistant',
47
- api: model.api,
48
- provider: model.provider,
49
- model: model.id,
50
- content: [],
51
- usage: createEmptyUsage(),
52
- stopReason: 'stop',
53
- timestamp: Date.now(),
54
- };
55
- }
56
- export function createTextContent(text = '') {
57
- return { type: 'text', text };
58
- }
59
- export function createImageContent(data, mimeType) {
60
- return { type: 'image', data, mimeType };
61
- }
62
- export function createToolCall(id, name) {
63
- return { type: 'toolCall', id, name, arguments: {}, rawArguments: '' };
64
- }
65
- export function createUserMessage(content) {
66
- return {
67
- role: 'user',
68
- content,
69
- timestamp: Date.now(),
70
- };
71
- }
72
- export function createToolResultMessage(toolCallId, toolName, content, isError = false) {
73
- return {
74
- role: 'toolResult',
75
- toolCallId,
76
- toolName,
77
- content,
78
- isError,
79
- timestamp: Date.now(),
80
- };
81
- }
82
- export function getMessageText(message) {
83
- return message.content
84
- .filter((block) => block.type === 'text')
85
- .map((block) => block.text)
86
- .join('');
87
- }
88
- const DEFAULT_DEFERRAL_TEXT = 'User did not respond. Continue.';
89
- /**
90
- * Synthesize toolResult messages for every toolCall that lacks both a decision
91
- * and a paired toolResult. Returns input unchanged (referentially equal) when
92
- * nothing needs synthesizing.
93
- *
94
- * Use case: user types a message instead of clicking approve/deny on a paused
95
- * tool. The agent can't resume on text alone โ€” every dangling toolCall needs
96
- * a result before the next request. Compose with sendMessages to forward the
97
- * conversation cleanly:
98
- *
99
- * await sendMessages([...injectDeferralResults(messages), createUserMessage(text)]);
100
- */
101
- export function injectDeferralResults(messages, optionsOrText = {}) {
102
- const opts = typeof optionsOrText === 'string' ? { deferralText: optionsOrText } : optionsOrText;
103
- const deferralText = opts.deferralText ?? DEFAULT_DEFERRAL_TEXT;
104
- const completed = new Set();
105
- for (const m of messages) {
106
- if (m.role === 'toolResult')
107
- completed.add(m.toolCallId);
108
- }
109
- const synthetic = [];
110
- for (const m of messages) {
111
- if (m.role !== 'assistant')
112
- continue;
113
- for (const block of m.content) {
114
- if (block.type !== 'toolCall')
115
- continue;
116
- if (completed.has(block.id))
117
- continue;
118
- if ('decision' in block && block.decision !== undefined)
119
- continue;
120
- const result = createToolResultMessage(block.id, block.name, [
121
- { type: 'text', text: deferralText },
122
- ]);
123
- if (opts.details !== undefined)
124
- result.details = opts.details;
125
- synthetic.push(result);
126
- }
127
- }
128
- if (synthetic.length === 0)
129
- return messages;
130
- return [...messages, ...synthetic];
131
- }
132
- export function cloneMessage(message) {
133
- return JSON.parse(JSON.stringify(message));
134
- }
135
- export function normalizeContext(context) {
136
- return {
137
- systemPrompt: context.systemPrompt,
138
- tools: context.tools ?? [],
139
- messages: context.messages.map((message) => ensureTimestamp(cloneMessage(message))),
140
- };
141
- }
142
- function ensureTimestamp(message) {
143
- if (typeof message.timestamp !== 'number') {
144
- message.timestamp = Date.now();
145
- }
146
- return message;
147
- }
package/esm/package.json DELETED
@@ -1 +0,0 @@
1
- {"type":"module"}
package/esm/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
package/event-stream.d.ts DELETED
@@ -1,19 +0,0 @@
1
- import type { AssistantMessage, AssistantMessageEvent, AssistantMessageEventStream } from './types.js';
2
- export declare class EventStream<TEvent, TResult = TEvent> implements AsyncIterable<TEvent> {
3
- private readonly isTerminal;
4
- private readonly extractResult;
5
- private readonly queue;
6
- private readonly waiting;
7
- private done;
8
- private readonly finalResultPromise;
9
- private resolveFinalResult;
10
- constructor(isTerminal: (event: TEvent) => boolean, extractResult: (event: TEvent) => TResult);
11
- push(event: TEvent): void;
12
- end(result?: TResult): void;
13
- [Symbol.asyncIterator](): AsyncIterator<TEvent>;
14
- result(): Promise<TResult>;
15
- }
16
- export declare class DefaultAssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> implements AssistantMessageEventStream {
17
- constructor();
18
- }
19
- export declare function createAssistantMessageEventStream(): DefaultAssistantMessageEventStream;
package/event-stream.js DELETED
@@ -1,83 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DefaultAssistantMessageEventStream = exports.EventStream = void 0;
4
- exports.createAssistantMessageEventStream = createAssistantMessageEventStream;
5
- class EventStream {
6
- isTerminal;
7
- extractResult;
8
- queue = [];
9
- waiting = [];
10
- done = false;
11
- finalResultPromise;
12
- resolveFinalResult;
13
- constructor(isTerminal, extractResult) {
14
- this.isTerminal = isTerminal;
15
- this.extractResult = extractResult;
16
- this.finalResultPromise = new Promise((resolve) => {
17
- this.resolveFinalResult = resolve;
18
- });
19
- }
20
- push(event) {
21
- if (this.done) {
22
- return;
23
- }
24
- if (this.isTerminal(event)) {
25
- this.done = true;
26
- this.resolveFinalResult(this.extractResult(event));
27
- }
28
- const waiter = this.waiting.shift();
29
- if (waiter) {
30
- waiter({ value: event, done: false });
31
- return;
32
- }
33
- this.queue.push(event);
34
- }
35
- end(result) {
36
- this.done = true;
37
- if (result !== undefined) {
38
- this.resolveFinalResult(result);
39
- }
40
- while (this.waiting.length > 0) {
41
- this.waiting.shift()({ value: undefined, done: true });
42
- }
43
- }
44
- async *[Symbol.asyncIterator]() {
45
- while (true) {
46
- if (this.queue.length > 0) {
47
- yield this.queue.shift();
48
- continue;
49
- }
50
- if (this.done) {
51
- return;
52
- }
53
- const next = await new Promise((resolve) => {
54
- this.waiting.push(resolve);
55
- });
56
- if (next.done) {
57
- return;
58
- }
59
- yield next.value;
60
- }
61
- }
62
- result() {
63
- return this.finalResultPromise;
64
- }
65
- }
66
- exports.EventStream = EventStream;
67
- class DefaultAssistantMessageEventStream extends EventStream {
68
- constructor() {
69
- super((event) => event.type === 'done' || event.type === 'error', (event) => {
70
- if (event.type === 'done') {
71
- return event.message;
72
- }
73
- if (event.type === 'error') {
74
- return event.error;
75
- }
76
- throw new Error('Unexpected terminal event');
77
- });
78
- }
79
- }
80
- exports.DefaultAssistantMessageEventStream = DefaultAssistantMessageEventStream;
81
- function createAssistantMessageEventStream() {
82
- return new DefaultAssistantMessageEventStream();
83
- }
package/messages.d.ts DELETED
@@ -1,33 +0,0 @@
1
- import type { AssistantMessage, Context, ImageContent, Message, ModelDescriptor, TextContent, ToolCallContent, ToolResultMessage, Usage, UserMessage } from './types.js';
2
- export declare function createEmptyUsage(): Usage;
3
- export declare function calculateUsageCost(model: ModelDescriptor, usage: Usage): void;
4
- export declare function snapshotUsage(usage: Usage): Usage;
5
- export declare function addUsage(target: Usage, delta: Usage): Usage;
6
- export declare function createAssistantMessage(model: ModelDescriptor): AssistantMessage;
7
- export declare function createTextContent(text?: string): TextContent;
8
- export declare function createImageContent(data: string, mimeType: string): ImageContent;
9
- export declare function createToolCall(id: string, name: string): ToolCallContent;
10
- export declare function createUserMessage(content: UserMessage['content']): UserMessage;
11
- export declare function createToolResultMessage(toolCallId: string, toolName: string, content: ToolResultMessage['content'], isError?: boolean): ToolResultMessage;
12
- export declare function getMessageText(message: AssistantMessage): string;
13
- export interface InjectDeferralResultsOptions {
14
- /** Text body for synthesized results. Defaults to a generic continue prompt. */
15
- deferralText?: string;
16
- /** Stamped onto each synthesized result's `details` field โ€” typically `{ deferred: true }` so renderers can hide a "Done" badge. */
17
- details?: unknown;
18
- }
19
- /**
20
- * Synthesize toolResult messages for every toolCall that lacks both a decision
21
- * and a paired toolResult. Returns input unchanged (referentially equal) when
22
- * nothing needs synthesizing.
23
- *
24
- * Use case: user types a message instead of clicking approve/deny on a paused
25
- * tool. The agent can't resume on text alone โ€” every dangling toolCall needs
26
- * a result before the next request. Compose with sendMessages to forward the
27
- * conversation cleanly:
28
- *
29
- * await sendMessages([...injectDeferralResults(messages), createUserMessage(text)]);
30
- */
31
- export declare function injectDeferralResults(messages: Message[], optionsOrText?: InjectDeferralResultsOptions | string): Message[];
32
- export declare function cloneMessage<TMessage extends Message>(message: TMessage): TMessage;
33
- export declare function normalizeContext(context: Context): Context;
package/messages.js DELETED
@@ -1,163 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createEmptyUsage = createEmptyUsage;
4
- exports.calculateUsageCost = calculateUsageCost;
5
- exports.snapshotUsage = snapshotUsage;
6
- exports.addUsage = addUsage;
7
- exports.createAssistantMessage = createAssistantMessage;
8
- exports.createTextContent = createTextContent;
9
- exports.createImageContent = createImageContent;
10
- exports.createToolCall = createToolCall;
11
- exports.createUserMessage = createUserMessage;
12
- exports.createToolResultMessage = createToolResultMessage;
13
- exports.getMessageText = getMessageText;
14
- exports.injectDeferralResults = injectDeferralResults;
15
- exports.cloneMessage = cloneMessage;
16
- exports.normalizeContext = normalizeContext;
17
- function createEmptyUsage() {
18
- return {
19
- input: 0,
20
- output: 0,
21
- reasoning: 0,
22
- cacheRead: 0,
23
- cacheWrite: 0,
24
- totalTokens: 0,
25
- cost: {
26
- input: 0,
27
- output: 0,
28
- cacheRead: 0,
29
- cacheWrite: 0,
30
- total: 0,
31
- },
32
- };
33
- }
34
- function calculateUsageCost(model, usage) {
35
- const schedule = model.cost;
36
- usage.cost.input = ((schedule?.input ?? 0) / 1_000_000) * usage.input;
37
- usage.cost.output = ((schedule?.output ?? 0) / 1_000_000) * usage.output;
38
- usage.cost.cacheRead = ((schedule?.cacheRead ?? 0) / 1_000_000) * usage.cacheRead;
39
- usage.cost.cacheWrite = ((schedule?.cacheWrite ?? 0) / 1_000_000) * usage.cacheWrite;
40
- usage.cost.total =
41
- usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
42
- }
43
- function snapshotUsage(usage) {
44
- return { ...usage, cost: { ...usage.cost } };
45
- }
46
- function addUsage(target, delta) {
47
- target.input += delta.input;
48
- target.output += delta.output;
49
- target.reasoning += delta.reasoning;
50
- target.cacheRead += delta.cacheRead;
51
- target.cacheWrite += delta.cacheWrite;
52
- target.totalTokens += delta.totalTokens;
53
- target.cost.input += delta.cost.input;
54
- target.cost.output += delta.cost.output;
55
- target.cost.cacheRead += delta.cost.cacheRead;
56
- target.cost.cacheWrite += delta.cost.cacheWrite;
57
- target.cost.total += delta.cost.total;
58
- return target;
59
- }
60
- function createAssistantMessage(model) {
61
- return {
62
- role: 'assistant',
63
- api: model.api,
64
- provider: model.provider,
65
- model: model.id,
66
- content: [],
67
- usage: createEmptyUsage(),
68
- stopReason: 'stop',
69
- timestamp: Date.now(),
70
- };
71
- }
72
- function createTextContent(text = '') {
73
- return { type: 'text', text };
74
- }
75
- function createImageContent(data, mimeType) {
76
- return { type: 'image', data, mimeType };
77
- }
78
- function createToolCall(id, name) {
79
- return { type: 'toolCall', id, name, arguments: {}, rawArguments: '' };
80
- }
81
- function createUserMessage(content) {
82
- return {
83
- role: 'user',
84
- content,
85
- timestamp: Date.now(),
86
- };
87
- }
88
- function createToolResultMessage(toolCallId, toolName, content, isError = false) {
89
- return {
90
- role: 'toolResult',
91
- toolCallId,
92
- toolName,
93
- content,
94
- isError,
95
- timestamp: Date.now(),
96
- };
97
- }
98
- function getMessageText(message) {
99
- return message.content
100
- .filter((block) => block.type === 'text')
101
- .map((block) => block.text)
102
- .join('');
103
- }
104
- const DEFAULT_DEFERRAL_TEXT = 'User did not respond. Continue.';
105
- /**
106
- * Synthesize toolResult messages for every toolCall that lacks both a decision
107
- * and a paired toolResult. Returns input unchanged (referentially equal) when
108
- * nothing needs synthesizing.
109
- *
110
- * Use case: user types a message instead of clicking approve/deny on a paused
111
- * tool. The agent can't resume on text alone โ€” every dangling toolCall needs
112
- * a result before the next request. Compose with sendMessages to forward the
113
- * conversation cleanly:
114
- *
115
- * await sendMessages([...injectDeferralResults(messages), createUserMessage(text)]);
116
- */
117
- function injectDeferralResults(messages, optionsOrText = {}) {
118
- const opts = typeof optionsOrText === 'string' ? { deferralText: optionsOrText } : optionsOrText;
119
- const deferralText = opts.deferralText ?? DEFAULT_DEFERRAL_TEXT;
120
- const completed = new Set();
121
- for (const m of messages) {
122
- if (m.role === 'toolResult')
123
- completed.add(m.toolCallId);
124
- }
125
- const synthetic = [];
126
- for (const m of messages) {
127
- if (m.role !== 'assistant')
128
- continue;
129
- for (const block of m.content) {
130
- if (block.type !== 'toolCall')
131
- continue;
132
- if (completed.has(block.id))
133
- continue;
134
- if ('decision' in block && block.decision !== undefined)
135
- continue;
136
- const result = createToolResultMessage(block.id, block.name, [
137
- { type: 'text', text: deferralText },
138
- ]);
139
- if (opts.details !== undefined)
140
- result.details = opts.details;
141
- synthetic.push(result);
142
- }
143
- }
144
- if (synthetic.length === 0)
145
- return messages;
146
- return [...messages, ...synthetic];
147
- }
148
- function cloneMessage(message) {
149
- return JSON.parse(JSON.stringify(message));
150
- }
151
- function normalizeContext(context) {
152
- return {
153
- systemPrompt: context.systemPrompt,
154
- tools: context.tools ?? [],
155
- messages: context.messages.map((message) => ensureTimestamp(cloneMessage(message))),
156
- };
157
- }
158
- function ensureTimestamp(message) {
159
- if (typeof message.timestamp !== 'number') {
160
- message.timestamp = Date.now();
161
- }
162
- return message;
163
- }
package/types.d.ts DELETED
@@ -1,232 +0,0 @@
1
- export type JsonPrimitive = string | number | boolean | null;
2
- export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
3
- export interface JsonObject {
4
- [key: string]: JsonValue | undefined;
5
- }
6
- export interface JsonSchema {
7
- $id?: string;
8
- $ref?: string;
9
- additionalProperties?: boolean | JsonSchema;
10
- allOf?: JsonSchema[];
11
- anyOf?: JsonSchema[];
12
- const?: JsonValue;
13
- default?: JsonValue;
14
- description?: string;
15
- enum?: JsonValue[];
16
- format?: string;
17
- items?: JsonSchema | JsonSchema[];
18
- maxItems?: number;
19
- maxLength?: number;
20
- maximum?: number;
21
- minItems?: number;
22
- minLength?: number;
23
- minimum?: number;
24
- oneOf?: JsonSchema[];
25
- pattern?: string;
26
- properties?: Record<string, JsonSchema>;
27
- required?: string[];
28
- title?: string;
29
- type?: string | string[];
30
- }
31
- export type InputCapability = 'text' | 'image';
32
- export interface CostSchedule {
33
- input?: number;
34
- output?: number;
35
- cacheRead?: number;
36
- cacheWrite?: number;
37
- }
38
- export interface OpenAICompatibleCompat {
39
- maxTokensField?: 'max_completion_tokens' | 'max_tokens';
40
- reasoningFormat?: 'none' | 'openai';
41
- supportsReasoningEffort?: boolean;
42
- supportsStrictToolSchema?: boolean;
43
- supportsUsageInStreaming?: boolean;
44
- toolCallIdFormat?: 'passthrough' | 'safe64' | 'mistral9';
45
- requiresToolResultName?: boolean;
46
- }
47
- export interface ModelDescriptor {
48
- id: string;
49
- name: string;
50
- api: string;
51
- provider: string;
52
- baseUrl: string;
53
- input: InputCapability[];
54
- reasoning: boolean;
55
- tools?: boolean;
56
- contextWindow?: number;
57
- maxOutputTokens?: number;
58
- cost?: CostSchedule;
59
- headers?: Record<string, string>;
60
- compat?: OpenAICompatibleCompat;
61
- }
62
- export interface TextContent {
63
- type: 'text';
64
- text: string;
65
- }
66
- export interface ImageContent {
67
- type: 'image';
68
- data: string;
69
- mimeType: string;
70
- }
71
- export interface ThinkingContent {
72
- type: 'thinking';
73
- thinking: string;
74
- signature?: string;
75
- }
76
- export interface ToolCallContent {
77
- type: 'toolCall';
78
- id: string;
79
- name: string;
80
- arguments: Record<string, JsonValue | undefined>;
81
- rawArguments?: string;
82
- decision?: unknown;
83
- }
84
- export interface Usage {
85
- input: number;
86
- output: number;
87
- reasoning: number;
88
- cacheRead: number;
89
- cacheWrite: number;
90
- totalTokens: number;
91
- cost: {
92
- input: number;
93
- output: number;
94
- cacheRead: number;
95
- cacheWrite: number;
96
- total: number;
97
- };
98
- }
99
- export type StopReason = 'stop' | 'length' | 'toolUse' | 'error' | 'aborted';
100
- export interface UserMessage {
101
- role: 'user';
102
- content: string | Array<TextContent | ImageContent>;
103
- timestamp: number;
104
- }
105
- export interface AssistantMessage {
106
- role: 'assistant';
107
- content: Array<TextContent | ThinkingContent | ToolCallContent>;
108
- api: string;
109
- provider: string;
110
- model: string;
111
- usage: Usage;
112
- stopReason: StopReason;
113
- errorMessage?: string;
114
- timestamp: number;
115
- }
116
- export interface ToolResultMessage<TDetails = unknown> {
117
- role: 'toolResult';
118
- toolCallId: string;
119
- toolName: string;
120
- content: Array<TextContent | ImageContent>;
121
- isError: boolean;
122
- details?: TDetails;
123
- timestamp: number;
124
- }
125
- export type Message = UserMessage | AssistantMessage | ToolResultMessage;
126
- export interface ToolDefinition<TSchema extends JsonSchema = JsonSchema> {
127
- name: string;
128
- description: string;
129
- parameters: TSchema;
130
- }
131
- export interface Context {
132
- systemPrompt?: string;
133
- messages: Message[];
134
- tools?: ToolDefinition[];
135
- }
136
- export type CacheRetention = 'none' | 'short' | 'long';
137
- export interface StreamOptions {
138
- apiKey?: string;
139
- cacheRetention?: CacheRetention;
140
- headers?: Record<string, string>;
141
- maxRetryDelayMs?: number;
142
- maxTokens?: number;
143
- metadata?: Record<string, JsonValue | undefined>;
144
- onPayload?: (payload: unknown) => void;
145
- reasoning?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
146
- sessionId?: string;
147
- signal?: AbortSignal;
148
- temperature?: number;
149
- }
150
- export type AssistantMessageEvent = {
151
- type: 'start';
152
- partial: AssistantMessage;
153
- } | {
154
- type: 'text_start';
155
- contentIndex: number;
156
- partial: AssistantMessage;
157
- } | {
158
- type: 'text_delta';
159
- contentIndex: number;
160
- delta: string;
161
- partial: AssistantMessage;
162
- } | {
163
- type: 'text_end';
164
- contentIndex: number;
165
- content: string;
166
- partial: AssistantMessage;
167
- } | {
168
- type: 'thinking_start';
169
- contentIndex: number;
170
- partial: AssistantMessage;
171
- } | {
172
- type: 'thinking_delta';
173
- contentIndex: number;
174
- delta: string;
175
- partial: AssistantMessage;
176
- } | {
177
- type: 'thinking_end';
178
- contentIndex: number;
179
- content: string;
180
- partial: AssistantMessage;
181
- } | {
182
- type: 'toolcall_start';
183
- contentIndex: number;
184
- partial: AssistantMessage;
185
- } | {
186
- type: 'toolcall_delta';
187
- contentIndex: number;
188
- delta: string;
189
- partial: AssistantMessage;
190
- } | {
191
- type: 'toolcall_end';
192
- contentIndex: number;
193
- toolCall: ToolCallContent;
194
- partial: AssistantMessage;
195
- } | {
196
- type: 'done';
197
- reason: Extract<StopReason, 'stop' | 'length' | 'toolUse'>;
198
- message: AssistantMessage;
199
- } | {
200
- type: 'error';
201
- reason: Extract<StopReason, 'error' | 'aborted'>;
202
- error: AssistantMessage;
203
- };
204
- export interface ProviderAdapter<TOptions extends StreamOptions = StreamOptions> {
205
- api: string;
206
- provider: string;
207
- createModel?: (modelId: string, overrides?: Partial<ModelDescriptor>) => ModelDescriptor;
208
- listModels?: (options?: Pick<StreamOptions, 'apiKey' | 'headers'>) => Promise<Array<ModelDescriptor | string>>;
209
- stream: (model: ModelDescriptor, context: Context, options?: TOptions) => AssistantMessageEventStream;
210
- }
211
- export interface LegacyChatMessage {
212
- role: 'system' | 'user' | 'assistant';
213
- content: string;
214
- }
215
- export interface LegacyGenerateInput {
216
- model: string;
217
- prompt?: string;
218
- messages?: LegacyChatMessage[];
219
- system?: string;
220
- stream?: boolean;
221
- temperature?: number;
222
- maxTokens?: number;
223
- }
224
- export interface LegacyStreamingOptions {
225
- onChunk?: (chunk: string) => void;
226
- onComplete?: () => void;
227
- onError?: (error: Error) => void;
228
- onStateChange?: (state: string) => void;
229
- }
230
- export interface AssistantMessageEventStream extends AsyncIterable<AssistantMessageEvent> {
231
- result(): Promise<AssistantMessage>;
232
- }
package/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });