@mupt-ai/dari-router 0.2.5 → 1.0.290

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +148 -55
  2. package/dist/auto_router.d.ts +1 -1
  3. package/dist/auto_router.js.map +1 -1
  4. package/dist/cache_scope.js +5 -5
  5. package/dist/cache_scope.js.map +1 -1
  6. package/dist/dari_policy.d.ts +0 -3
  7. package/dist/dari_policy.js +2 -2
  8. package/dist/dari_policy.js.map +1 -1
  9. package/dist/eval_score_imputation.js +2 -0
  10. package/dist/eval_score_imputation.js.map +1 -1
  11. package/dist/framework_router.d.ts +2 -1
  12. package/dist/framework_router.js +264 -47
  13. package/dist/framework_router.js.map +1 -1
  14. package/dist/framework_types.d.ts +9 -0
  15. package/dist/framework_validation.js +1 -0
  16. package/dist/framework_validation.js.map +1 -1
  17. package/dist/gateway_executor.d.ts +16 -0
  18. package/dist/gateway_executor.js +523 -0
  19. package/dist/gateway_executor.js.map +1 -0
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +1 -1
  22. package/dist/index.js.map +1 -1
  23. package/examples/auto_router.ts +16 -11
  24. package/examples/basic_route.ts +19 -19
  25. package/examples/lease_stores.ts +21 -15
  26. package/examples/managed/README.md +3 -4
  27. package/examples/managed/byok-router/router.yml +4 -4
  28. package/examples/managed/custom-rules-router/router.yml +9 -9
  29. package/examples/managed/dari/router.yml +3 -2
  30. package/package.json +5 -14
  31. package/dist/pi_context.d.ts +0 -4
  32. package/dist/pi_context.js +0 -237
  33. package/dist/pi_context.js.map +0 -1
  34. package/dist/pi_options.d.ts +0 -3
  35. package/dist/pi_options.js +0 -300
  36. package/dist/pi_options.js.map +0 -1
  37. package/dist/pi_output.d.ts +0 -4
  38. package/dist/pi_output.js +0 -328
  39. package/dist/pi_output.js.map +0 -1
  40. package/dist/pi_runtime.d.ts +0 -3
  41. package/dist/pi_runtime.js +0 -163
  42. package/dist/pi_runtime.js.map +0 -1
  43. package/dist/pi_types.d.ts +0 -35
  44. package/dist/pi_types.js +0 -2
  45. package/dist/pi_types.js.map +0 -1
  46. package/examples/managed/eval-router/README.md +0 -18
  47. package/examples/managed/eval-router/router.yml +0 -11
  48. package/examples/pi_runtime.ts +0 -55
@@ -12,9 +12,9 @@ import {
12
12
  type RouteInput,
13
13
  } from "../src/policy-engine.js";
14
14
 
15
- const FABLE = "anthropic/claude-fable-5";
16
- const SOL = "openai/gpt-5.6-sol";
17
- const GLM = "zai-org/GLM-5.2";
15
+ const FABLE = "anthropic/claude-fable-5-1";
16
+ const SOL = "openai/gpt-6.1-sol";
17
+ const DEEPSEEK = "deepseek-ai/DeepSeek-V4.1-Flash-1017";
18
18
 
19
19
  const metadata: Record<string, CandidateModelMetadata> = {
20
20
  [FABLE]: {
@@ -23,7 +23,7 @@ const metadata: Record<string, CandidateModelMetadata> = {
23
23
  supportsImageInput: true,
24
24
  supportsHostedWebSearch: false,
25
25
  supportsStructuredOutput: false,
26
- supportedThinkingLevels: ["medium", "high", "max"],
26
+ supportedThinkingLevels: ["low", "medium", "high", "xhigh", "max"],
27
27
  },
28
28
  [SOL]: {
29
29
  provider: "openai",
@@ -31,27 +31,27 @@ const metadata: Record<string, CandidateModelMetadata> = {
31
31
  supportsImageInput: true,
32
32
  supportsHostedWebSearch: true,
33
33
  supportsStructuredOutput: true,
34
- supportedThinkingLevels: ["low", "medium", "high", "xhigh"],
34
+ supportedThinkingLevels: ["low", "medium", "high", "xhigh", "max"],
35
35
  },
36
- [GLM]: {
36
+ [DEEPSEEK]: {
37
37
  provider: "fireworks",
38
- api: "openai-completions",
38
+ api: "anthropic-messages",
39
39
  supportsImageInput: false,
40
40
  supportsHostedWebSearch: false,
41
41
  supportsStructuredOutput: true,
42
- supportedThinkingLevels: ["off", "medium"],
42
+ supportedThinkingLevels: ["off", "high", "max"],
43
43
  },
44
44
  };
45
45
 
46
- // Illustrative $/MTok rates; supply your real catalog rates in production.
46
+ // $/MTok rates from the provider model mappings; supply your own catalog in production.
47
47
  const pricing: Record<string, ModelPricing> = {
48
- [FABLE]: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
49
- [SOL]: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },
50
- [GLM]: { input: 0.6, output: 2.2, cacheRead: 0.15, cacheWrite: 0.6 },
48
+ [FABLE]: { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 },
49
+ [SOL]: { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
50
+ [DEEPSEEK]: { input: 0.3, output: 1.2, cacheRead: 0.006, cacheWrite: 0 },
51
51
  };
52
52
 
53
53
  const input: RouteInput = {
54
- candidateModels: [FABLE, SOL, GLM],
54
+ candidateModels: [FABLE, SOL, DEEPSEEK],
55
55
  metadataLookup: (modelId) => {
56
56
  const entry = metadata[modelId];
57
57
  if (!entry) throw new Error(`unknown model ${modelId}`);
@@ -65,7 +65,7 @@ const input: RouteInput = {
65
65
  modelThinkingLevels: {
66
66
  [FABLE]: ["high"],
67
67
  [SOL]: ["medium", "high"],
68
- [GLM]: ["off", "medium"],
68
+ [DEEPSEEK]: ["off", "high"],
69
69
  },
70
70
  messages: [
71
71
  { role: "system", content: "You are a helpful assistant." },
@@ -77,7 +77,7 @@ const input: RouteInput = {
77
77
  chainsByModel: new Map([
78
78
  [FABLE, []],
79
79
  [SOL, []],
80
- [GLM, []],
80
+ [DEEPSEEK, []],
81
81
  ]),
82
82
  prefixHits: [],
83
83
  nowMs: Date.now(),
@@ -92,11 +92,11 @@ const input: RouteInput = {
92
92
  scores: [
93
93
  { model_id: FABLE, score: 87, notes: "high row", thinking_level: "high" },
94
94
  { model_id: SOL, score: 78, notes: "generic row" },
95
- { model_id: GLM, score: 64, notes: "medium row", thinking_level: "medium" },
95
+ { model_id: DEEPSEEK, score: 64, notes: "high row", thinking_level: "high" },
96
96
  ],
97
97
  },
98
98
  ],
99
- selectorModel: "openai/gpt-5.6-luna",
99
+ selectorModel: "openai/gpt-6-luna",
100
100
  selectorContextWindowChars: 400_000,
101
101
  };
102
102
 
@@ -117,8 +117,8 @@ console.log(
117
117
  // A real host would POST selectorRequest to an OpenAI-compatible endpoint.
118
118
  // This scripted selector always picks the cheapest viable pair.
119
119
  const selectorOutput = JSON.stringify({
120
- selected_model: GLM,
121
- reasoning_effort: "medium",
120
+ selected_model: DEEPSEEK,
121
+ reasoning_effort: "high",
122
122
  reason: "Simple summarization task; the cheapest candidate suffices.",
123
123
  fallback_model: SOL,
124
124
  fallback_reasoning_effort: "medium",
@@ -47,13 +47,15 @@ export function redisLeaseStore(redis: RedisLike, keyPrefix = "router-lease:"):
47
47
  // cache_key text primary key,
48
48
  // model text not null,
49
49
  // reasoning_effort text not null,
50
+ // start_turn int not null,
50
51
  // turns_remaining int not null,
51
52
  // expires_at bigint not null
52
53
  // );
53
54
  //
54
55
  // The router re-checks expiresAt itself before honoring a lease, so a lazy
55
- // pruneExpired (or a cron) is safe. If concurrent same-cacheKey requests
56
- // matter at your scale, do the turn decrement in SQL behind this interface.
56
+ // pruneExpired (or a cron) is safe. Leases hold by conversation turn, which
57
+ // the router reads from each request, so concurrent requests need no
58
+ // read-modify-write.
57
59
 
58
60
  type SqlLike = {
59
61
  query(text: string, params: unknown[]): Promise<{ rows: Record<string, unknown>[] }>;
@@ -63,7 +65,7 @@ export function postgresLeaseStore(sql: SqlLike): LeaseStore {
63
65
  return {
64
66
  async get(cacheKey) {
65
67
  const { rows } = await sql.query(
66
- "select model, reasoning_effort, turns_remaining, expires_at from router_leases where cache_key = $1",
68
+ "select model, reasoning_effort, start_turn, turns_remaining, expires_at from router_leases where cache_key = $1",
67
69
  [cacheKey],
68
70
  );
69
71
  const row = rows[0];
@@ -71,20 +73,22 @@ export function postgresLeaseStore(sql: SqlLike): LeaseStore {
71
73
  return {
72
74
  model: String(row.model),
73
75
  reasoningEffort: row.reasoning_effort as RouterLease["reasoningEffort"],
76
+ startTurn: Number(row.start_turn),
74
77
  turnsRemaining: Number(row.turns_remaining),
75
78
  expiresAt: Number(row.expires_at),
76
79
  };
77
80
  },
78
81
  async set(cacheKey, lease) {
79
82
  await sql.query(
80
- `insert into router_leases (cache_key, model, reasoning_effort, turns_remaining, expires_at)
81
- values ($1, $2, $3, $4, $5)
83
+ `insert into router_leases (cache_key, model, reasoning_effort, start_turn, turns_remaining, expires_at)
84
+ values ($1, $2, $3, $4, $5, $6)
82
85
  on conflict (cache_key) do update set
83
86
  model = excluded.model,
84
87
  reasoning_effort = excluded.reasoning_effort,
88
+ start_turn = excluded.start_turn,
85
89
  turns_remaining = excluded.turns_remaining,
86
90
  expires_at = excluded.expires_at`,
87
- [cacheKey, lease.model, lease.reasoningEffort, lease.turnsRemaining, lease.expiresAt],
91
+ [cacheKey, lease.model, lease.reasoningEffort, lease.startTurn, lease.turnsRemaining, lease.expiresAt],
88
92
  );
89
93
  },
90
94
  async delete(cacheKey) {
@@ -136,24 +140,26 @@ const models = [{ id: "demo/model", executor: "demo", reasoningEfforts: ["off" a
136
140
  const sharedStore = redisLeaseStore(fakeRedis());
137
141
  const routerOptions = { models, policy, executors: { demo: executor }, leaseStore: sharedStore };
138
142
 
139
- const ask = (router: { fetch: (request: Request) => Promise<Response> }) =>
143
+ const ask = (
144
+ router: { fetch: (request: Request) => Promise<Response> },
145
+ messages: Array<{ role: string; content: string }>,
146
+ ) =>
140
147
  router.fetch(
141
148
  new Request("https://example.test/v1/chat/completions", {
142
149
  method: "POST",
143
150
  headers: { "Content-Type": "application/json" },
144
- body: JSON.stringify({
145
- model: "dari/routing",
146
- prompt_cache_key: "conversation-1",
147
- messages: [{ role: "user", content: "hello" }],
148
- }),
151
+ body: JSON.stringify({ model: "dari/routing", prompt_cache_key: "conversation-1", messages }),
149
152
  }),
150
153
  );
151
154
 
155
+ const history = [{ role: "user", content: "hello" }];
152
156
  const first = createRouter(routerOptions);
153
- const turn1 = await (await ask(first)).json() as { dari_routing: { reason: string } };
157
+ const turn1 = await (await ask(first, history)).json() as { dari_routing: { reason: string } };
154
158
  console.log("turn 1 (fresh process): ", turn1.dari_routing.reason);
155
159
 
156
- // "Restart": a brand-new router instance sharing only the external store.
160
+ // "Restart": a brand-new router instance sharing only the external store
161
+ // serves the conversation's next turn from the lease.
162
+ history.push({ role: "assistant", content: turn1.dari_routing.reason }, { role: "user", content: "again" });
157
163
  const second = createRouter(routerOptions);
158
- const turn2 = await (await ask(second)).json() as { dari_routing: { reason: string } };
164
+ const turn2 = await (await ask(second, history)).json() as { dari_routing: { reason: string } };
159
165
  console.log("turn 2 (new process): ", turn2.dari_routing.reason);
@@ -4,10 +4,10 @@ Runnable `router.yml` manifests for Dari's managed router path. TypeScript frame
4
4
 
5
5
  ## Prerequisites
6
6
 
7
- Install the [Dari CLI](https://github.com/mupt-ai/dari-cli), sign in, and inspect the current model catalog:
7
+ Install the [Dari CLI](https://github.com/mupt-ai/dari), sign in, and inspect the current model catalog:
8
8
 
9
9
  ```bash
10
- curl -fsSL https://raw.githubusercontent.com/mupt-ai/dari-cli/main/install.sh | bash
10
+ curl -fsSL https://raw.githubusercontent.com/mupt-ai/dari/main/install.sh | bash
11
11
  dari auth login
12
12
  dari router models
13
13
  ```
@@ -19,7 +19,6 @@ Your organization needs access to the providers and models used by an example. F
19
19
  - [`dari/`](dari) — automatic selection with managed provider credentials.
20
20
  - [`byok-router/`](byok-router) — automatic selection with a provider key from your environment.
21
21
  - [`custom-rules-router/`](custom-rules-router) — natural-language rules with explicit model and reasoning-level constraints.
22
- - [`eval-router/`](eval-router) — automatic selection informed by an organization eval scorecard.
23
22
 
24
23
  ## Create And Call A Router
25
24
 
@@ -47,4 +46,4 @@ Run `dari router models` before editing a manifest. Model IDs and reasoning leve
47
46
 
48
47
  ## Adding An Example
49
48
 
50
- Each example is a self-contained directory containing a `README.md` and `router.yml`. Keep one managed-router concept per example. Use `provider_key_envs` for BYOK examples, never commit provider credentials or organization-specific eval IDs, and validate changes against a test organization with `dari router create <example>/router.yml`.
49
+ Each example is a self-contained directory containing a `README.md` and `router.yml`. Keep one managed-router concept per example. Use `provider_key_envs` for BYOK examples, never commit provider credentials, and validate changes against a test organization with `dari router create <example>/router.yml`.
@@ -1,10 +1,10 @@
1
1
  name: Example BYOK Router
2
2
  enabled_models:
3
- - openai/gpt-5.6-sol
4
- - zai-org/GLM-5.2
3
+ - openai/gpt-6.1-sol
4
+ - deepseek-ai/DeepSeek-V4.1-Flash-1017
5
5
  model_providers:
6
- openai/gpt-5.6-sol: openai
7
- zai-org/GLM-5.2: fireworks
6
+ openai/gpt-6.1-sol: openai
7
+ deepseek-ai/DeepSeek-V4.1-Flash-1017: fireworks
8
8
  provider_key_sources:
9
9
  openai: managed
10
10
  fireworks: user
@@ -1,13 +1,13 @@
1
1
  name: Example Custom Rules Router
2
2
  enabled_models:
3
- - openai/gpt-5.6-sol
4
- - deepseek-ai/DeepSeek-V4.1-Flash
3
+ - openai/gpt-6.1-sol
4
+ - deepseek-ai/DeepSeek-V4.1-Flash-1017
5
5
  model_providers:
6
- openai/gpt-5.6-sol: openai
7
- deepseek-ai/DeepSeek-V4.1-Flash: fireworks
6
+ openai/gpt-6.1-sol: openai
7
+ deepseek-ai/DeepSeek-V4.1-Flash-1017: fireworks
8
8
  model_thinking_levels:
9
- openai/gpt-5.6-sol: [low, medium, high]
10
- deepseek-ai/DeepSeek-V4.1-Flash: [off]
9
+ openai/gpt-6.1-sol: [low, medium, high]
10
+ deepseek-ai/DeepSeek-V4.1-Flash-1017: [off]
11
11
  provider_key_sources:
12
12
  openai: managed
13
13
  fireworks: managed
@@ -15,10 +15,10 @@ routing_strategy: custom
15
15
  custom_config:
16
16
  rules:
17
17
  - when: planning, architecture, or difficult debugging
18
- use: openai/gpt-5.6-sol
18
+ use: openai/gpt-6.1-sol
19
19
  thinking_level: high
20
20
  - when: short questions and straightforward implementation
21
- use: deepseek-ai/DeepSeek-V4.1-Flash
21
+ use: deepseek-ai/DeepSeek-V4.1-Flash-1017
22
22
  thinking_level: off
23
- default: deepseek-ai/DeepSeek-V4.1-Flash
23
+ default: deepseek-ai/DeepSeek-V4.1-Flash-1017
24
24
  default_thinking_level: off
@@ -1,7 +1,8 @@
1
1
  name: Example Dari Router
2
2
  enabled_models:
3
- - openai/gpt-5.6-sol
4
- - anthropic/claude-sonnet-5
3
+ - openai/gpt-6.1-sol
4
+ - anthropic/claude-opus-5-5
5
+ - anthropic/claude-haiku-5-5
5
6
  provider_key_sources:
6
7
  openai: managed
7
8
  anthropic: managed
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@mupt-ai/dari-router",
3
- "version": "0.2.5",
4
- "description": "End-to-end TypeScript framework for routing across LLMs with built-in Pi AI execution and pluggable policies and executors.",
3
+ "version": "1.0.290",
4
+ "description": "TypeScript framework for routing OpenAI and Anthropic requests across LLMs with pluggable policies and executors.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "git+https://github.com/mupt-ai/dari-router.git"
8
+ "url": "git+https://github.com/mupt-ai/dari.git",
9
+ "directory": "packages/router"
9
10
  },
10
11
  "homepage": "https://docs.dari.dev/framework/overview",
11
12
  "bugs": {
12
- "url": "https://github.com/mupt-ai/dari-router/issues"
13
+ "url": "https://github.com/mupt-ai/dari/issues"
13
14
  },
14
15
  "keywords": [
15
16
  "llm",
@@ -61,21 +62,11 @@
61
62
  "typecheck": "tsc --noEmit",
62
63
  "test": "bun test",
63
64
  "example": "bun run examples/create_router.ts",
64
- "example:pi": "bun run examples/pi_runtime.ts",
65
65
  "example:dari-policy": "bun run examples/dari_policy.ts",
66
66
  "example:decision-pipeline": "bun run examples/basic_route.ts",
67
67
  "example:lease-stores": "bun run examples/lease_stores.ts"
68
68
  },
69
- "peerDependencies": {
70
- "@mupt-ai/pi-ai": ">=1.1.0-mupt.1 <2.0.0"
71
- },
72
- "peerDependenciesMeta": {
73
- "@mupt-ai/pi-ai": {
74
- "optional": true
75
- }
76
- },
77
69
  "devDependencies": {
78
- "@mupt-ai/pi-ai": "1.1.0-mupt.2",
79
70
  "@types/bun": "^1.3.4",
80
71
  "@types/node": "^24.10.2",
81
72
  "typescript": "^5.6.3"
@@ -1,4 +0,0 @@
1
- import type { Context } from "@mupt-ai/pi-ai";
2
- import type { RouterRequest } from "./framework_types.js";
3
- import type { PiModel } from "./pi_types.js";
4
- export declare function piContext(request: RouterRequest, model: PiModel): Context;
@@ -1,237 +0,0 @@
1
- import { RouterFrameworkError } from "./framework_error.js";
2
- import { encodeOpenAIReasoningSignature } from "./pi_reasoning_signature.js";
3
- import { isRecord } from "./types.js";
4
- import { compatibleProviderContinuation, isOpenAIResponsesApi, } from "./continuation_state.js";
5
- export function piContext(request, model) {
6
- const system = [];
7
- const messages = [];
8
- const calls = new Map();
9
- const timestamp = Date.now();
10
- let assistant;
11
- let sawConversationItem = false;
12
- const flushAssistant = () => {
13
- if (assistant === undefined)
14
- return;
15
- if (assistant.content.length === 0)
16
- assistant.content.push({ type: "text", text: "" });
17
- assistant.stopReason = assistant.content.some((part) => part.type === "toolCall")
18
- ? "toolUse"
19
- : "stop";
20
- messages.push(assistant);
21
- assistant = undefined;
22
- };
23
- const currentAssistant = () => {
24
- assistant ??= {
25
- role: "assistant",
26
- content: [],
27
- api: model.api,
28
- provider: model.provider,
29
- model: model.id,
30
- usage: zeroPiUsage(),
31
- stopReason: "stop",
32
- timestamp,
33
- };
34
- return assistant;
35
- };
36
- for (const item of request.items) {
37
- if (item.type === "message" && (item.role === "system" || item.role === "developer")) {
38
- flushAssistant();
39
- const text = systemText(item.content);
40
- if (!text)
41
- continue;
42
- if (!sawConversationItem) {
43
- // Leading preamble is identical on every request, so folding it into
44
- // the system prompt keeps the provider payload prefix stable.
45
- system.push(text);
46
- continue;
47
- }
48
- // Mid-conversation system/developer notes arrive between turns (Claude
49
- // Code appends a `<total_tokens>` reminder after every tool result).
50
- // Folding them into the system prompt mutates the front of the provider
51
- // payload, so prefix-matching prompt caches miss and re-write the whole
52
- // conversation at cache-write prices. Keep them positional instead.
53
- appendPositionalNote(messages, text, timestamp);
54
- continue;
55
- }
56
- sawConversationItem = true;
57
- if (item.type === "message" && item.role === "user") {
58
- flushAssistant();
59
- appendUserMessage(messages, piContent(item.content, "user message"), timestamp);
60
- continue;
61
- }
62
- if (item.type === "message") {
63
- const pending = currentAssistant();
64
- pending.content.push(...item.content.map((part) => {
65
- if (part.type !== "text") {
66
- throw new RouterFrameworkError("invalid_request", "Pi does not support image content in assistant messages.", "pi_assistant_image_unsupported");
67
- }
68
- return { type: "text", text: part.text };
69
- }));
70
- continue;
71
- }
72
- if (item.type === "tool_call") {
73
- const argumentsValue = toolArguments(item.arguments, item.id);
74
- currentAssistant().content.push({
75
- type: "toolCall",
76
- id: item.id,
77
- name: item.name,
78
- arguments: argumentsValue,
79
- });
80
- calls.set(item.id, item.name);
81
- continue;
82
- }
83
- if (item.type === "reasoning") {
84
- const target = {
85
- provider: model.provider,
86
- api: model.api,
87
- model: model.id,
88
- };
89
- const continuation = compatibleProviderContinuation(item.continuation, target);
90
- if (continuation) {
91
- currentAssistant().content.push(thinkingContent(item, continuation));
92
- }
93
- else {
94
- const readable = [...(item.summary ?? []), ...item.content].join("\n");
95
- if (readable) {
96
- // Cross-provider: the encrypted blob is not replayable, so carry the
97
- // readable reasoning as plain text instead of dropping the prior
98
- // turn's chain-of-thought entirely.
99
- currentAssistant().content.push({ type: "text", text: readable });
100
- }
101
- }
102
- continue;
103
- }
104
- if (item.type === "hosted_tool_call") {
105
- if (!isOpenAIResponsesApi(model.api)) {
106
- // Dropping the item would silently lose a conversation turn.
107
- throw new RouterFrameworkError("configuration", `Hosted tool calls are not representable on the '${model.api}' API; route hosted-tool conversations to a Responses-API model.`, "hosted_tool_call_unrepresentable");
108
- }
109
- currentAssistant().content.push({
110
- type: "providerItem",
111
- item: item.payload,
112
- });
113
- continue;
114
- }
115
- flushAssistant();
116
- messages.push({
117
- role: "toolResult",
118
- toolCallId: item.toolCallId,
119
- toolName: calls.get(item.toolCallId) ?? "tool",
120
- content: piContent(item.content, `tool result '${item.toolCallId}'`),
121
- isError: item.isError ?? false,
122
- timestamp,
123
- });
124
- }
125
- flushAssistant();
126
- const tools = request.tools.map((tool) => ({
127
- name: tool.name,
128
- description: tool.description ?? "",
129
- parameters: tool.inputSchema,
130
- }));
131
- return {
132
- ...(system.length === 0 ? {} : { systemPrompt: system.join("\n\n") }),
133
- messages,
134
- ...(tools.length === 0 ? {} : { tools }),
135
- };
136
- }
137
- function thinkingContent(item, continuation) {
138
- if (continuation.kind === "openai_reasoning") {
139
- const providerItemId = continuation.providerItemId ?? item.id;
140
- return {
141
- type: "thinking",
142
- thinking: [...(item.summary ?? []), ...item.content].join("\n"),
143
- thinkingSignature: encodeOpenAIReasoningSignature({
144
- ...(providerItemId ? { id: providerItemId } : {}),
145
- summary: item.summary ?? [],
146
- content: item.content,
147
- encryptedContent: continuation.encryptedContent,
148
- }),
149
- };
150
- }
151
- if (continuation.kind === "anthropic_thinking") {
152
- return {
153
- type: "thinking",
154
- thinking: continuation.thinking,
155
- thinkingSignature: continuation.signature,
156
- };
157
- }
158
- return {
159
- type: "thinking",
160
- thinking: "",
161
- thinkingSignature: continuation.data,
162
- redacted: true,
163
- };
164
- }
165
- function appendPositionalNote(messages, text, timestamp) {
166
- const previous = messages.at(-1);
167
- if (previous?.role === "toolResult") {
168
- previous.content = [...piContentBlocks(previous.content), { type: "text", text }];
169
- return;
170
- }
171
- appendUserMessage(messages, [{ type: "text", text }], timestamp);
172
- }
173
- function appendUserMessage(messages, content, timestamp) {
174
- const previous = messages.at(-1);
175
- if (previous?.role === "user") {
176
- previous.content = [...piContentBlocks(previous.content), ...piContentBlocks(content)];
177
- return;
178
- }
179
- messages.push({ role: "user", content, timestamp });
180
- }
181
- function piContentBlocks(content) {
182
- return typeof content === "string" ? [{ type: "text", text: content }] : content;
183
- }
184
- function systemText(content) {
185
- return content.map((part) => {
186
- if (part.type !== "text") {
187
- throw new RouterFrameworkError("invalid_request", "Pi does not support image content in system or developer messages.", "pi_system_image_unsupported");
188
- }
189
- return part.text;
190
- }).join("");
191
- }
192
- function piContent(content, location) {
193
- return content.map((part) => {
194
- if (part.type === "text")
195
- return { type: "text", text: part.text };
196
- const image = dataImage(part.url);
197
- if (image === null) {
198
- throw new RouterFrameworkError("invalid_request", `Pi ${location} images must use base64 data URLs.`, "pi_remote_image_unsupported");
199
- }
200
- return { type: "image", data: image.data, mimeType: image.mimeType };
201
- });
202
- }
203
- function dataImage(url) {
204
- const match = /^data:(image\/[a-z0-9.+-]+);base64,([a-z0-9+/=\s]+)$/i.exec(url);
205
- if (match === null)
206
- return null;
207
- return { mimeType: match[1], data: match[2].replace(/\s/g, "") };
208
- }
209
- function toolArguments(value, id) {
210
- if (typeof value !== "string")
211
- return value;
212
- // Providers emit "" for zero-argument tool calls; replay it as {}.
213
- if (value === "")
214
- return {};
215
- let parsed;
216
- try {
217
- parsed = JSON.parse(value);
218
- }
219
- catch (error) {
220
- throw new RouterFrameworkError("invalid_request", `Tool call '${id}' arguments must be valid JSON.`, "pi_tool_arguments_invalid", undefined, { cause: error });
221
- }
222
- if (!isRecord(parsed)) {
223
- throw new RouterFrameworkError("invalid_request", `Tool call '${id}' arguments must be a JSON object.`, "pi_tool_arguments_invalid");
224
- }
225
- return parsed;
226
- }
227
- function zeroPiUsage() {
228
- return {
229
- input: 0,
230
- output: 0,
231
- cacheRead: 0,
232
- cacheWrite: 0,
233
- totalTokens: 0,
234
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
235
- };
236
- }
237
- //# sourceMappingURL=pi_context.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pi_context.js","sourceRoot":"","sources":["../src/pi_context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAMtC,OAAO,EACL,8BAA8B,EAC9B,oBAAoB,GAErB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,UAAU,SAAS,CAAC,OAAsB,EAAE,KAAc;IAC9D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,SAAkF,CAAC;IACvF,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAEhC,MAAM,cAAc,GAAG,GAAG,EAAE;QAC1B,IAAI,SAAS,KAAK,SAAS;YAAE,OAAO;QACpC,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACvF,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC;YAC/E,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,CAAC;QACX,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzB,SAAS,GAAG,SAAS,CAAC;IACxB,CAAC,CAAC;IACF,MAAM,gBAAgB,GAAG,GAAG,EAAE;QAC5B,SAAS,KAAK;YACZ,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,KAAK,CAAC,EAAE;YACf,KAAK,EAAE,WAAW,EAAE;YACpB,UAAU,EAAE,MAAM;YAClB,SAAS;SACV,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;YACrF,cAAc,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtC,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACzB,qEAAqE;gBACrE,8DAA8D;gBAC9D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClB,SAAS;YACX,CAAC;YACD,uEAAuE;YACvE,qEAAqE;YACrE,wEAAwE;YACxE,wEAAwE;YACxE,oEAAoE;YACpE,oBAAoB,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAChD,SAAS;QACX,CAAC;QACD,mBAAmB,GAAG,IAAI,CAAC;QAC3B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACpD,cAAc,EAAE,CAAC;YACjB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,SAAS,CAAC,CAAC;YAChF,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;YACnC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBAChD,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACzB,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,EACjB,0DAA0D,EAC1D,gCAAgC,CACjC,CAAC;gBACJ,CAAC;gBACD,OAAO,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;YACpD,CAAC,CAAC,CAAC,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC9B,MAAM,cAAc,GAAG,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9D,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC9B,IAAI,EAAE,UAAU;gBAChB,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,SAAS,EAAE,cAA4B;aACxC,CAAC,CAAC;YACH,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC9B,MAAM,MAAM,GAA2B;gBACrC,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,KAAK,EAAE,KAAK,CAAC,EAAE;aAChB,CAAC;YACF,MAAM,YAAY,GAAG,8BAA8B,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YAC/E,IAAI,YAAY,EAAE,CAAC;gBACjB,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;YACvE,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvE,IAAI,QAAQ,EAAE,CAAC;oBACb,qEAAqE;oBACrE,iEAAiE;oBACjE,oCAAoC;oBACpC,gBAAgB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACpE,CAAC;YACH,CAAC;YACD,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACrC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrC,6DAA6D;gBAC7D,MAAM,IAAI,oBAAoB,CAC5B,eAAe,EACf,mDAAmD,KAAK,CAAC,GAAG,kEAAkE,EAC9H,kCAAkC,CACnC,CAAC;YACJ,CAAC;YACA,gBAAgB,EAAE,CAAC,OAAqD,CAAC,IAAI,CAAC;gBAC7E,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,IAAI,CAAC,OAAO;aACnB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,cAAc,EAAE,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,YAAY;YAClB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,MAAM;YAC9C,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,IAAI,CAAC,UAAU,GAAG,CAAC;YACpE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK;YAC9B,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IACD,cAAc,EAAE,CAAC;IAEjB,MAAM,KAAK,GAAW,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjD,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;QACnC,UAAU,EAAE,IAAI,CAAC,WAAiC;KACnD,CAAC,CAAC,CAAC;IACJ,OAAO;QACL,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACrE,QAAQ;QACR,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CACtB,IAAoE,EACpE,YAAuC;IAEvC,IAAI,YAAY,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAC7C,MAAM,cAAc,GAAG,YAAY,CAAC,cAAc,IAAI,IAAI,CAAC,EAAE,CAAC;QAC9D,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/D,iBAAiB,EAAE,8BAA8B,CAAC;gBAChD,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE;gBAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,gBAAgB,EAAE,YAAY,CAAC,gBAAgB;aAChD,CAAC;SACH,CAAC;IACJ,CAAC;IACD,IAAI,YAAY,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;QAC/C,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,YAAY,CAAC,QAAQ;YAC/B,iBAAiB,EAAE,YAAY,CAAC,SAAS;SAC1C,CAAC;IACJ,CAAC;IACD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,EAAE;QACZ,iBAAiB,EAAE,YAAY,CAAC,IAAI;QACpC,QAAQ,EAAE,IAAI;KACf,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAC3B,QAA6B,EAC7B,IAAY,EACZ,SAAiB;IAEjB,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;QACpC,QAAQ,CAAC,OAAO,GAAG,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,OAAO;IACT,CAAC;IACD,iBAAiB,CAAC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,iBAAiB,CACxB,QAA6B,EAC7B,OAA0E,EAC1E,SAAiB;IAEjB,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,QAAQ,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,OAAO,GAAG,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;QACvF,OAAO;IACT,CAAC;IACD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,eAAe,CACtB,OAAyF;IAEzF,OAAO,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AACnF,CAAC;AAED,SAAS,UAAU,CAAC,OAAiC;IACnD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,EACjB,oEAAoE,EACpE,6BAA6B,CAC9B,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAChB,OAAiC,EACjC,QAAgB;IAEhB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;QACnE,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,EACjB,MAAM,QAAQ,oCAAoC,EAClD,6BAA6B,CAC9B,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,MAAM,KAAK,GAAG,uDAAuD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;AACrE,CAAC;AAED,SAAS,aAAa,CAAC,KAAuC,EAAE,EAAU;IACxE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,mEAAmE;IACnE,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAC5B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,EACjB,cAAc,EAAE,iCAAiC,EACjD,2BAA2B,EAC3B,SAAS,EACT,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,oBAAoB,CAC5B,iBAAiB,EACjB,cAAc,EAAE,oCAAoC,EACpD,2BAA2B,CAC5B,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,WAAW;IAClB,OAAO;QACL,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,CAAC;QACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;KACrE,CAAC;AACJ,CAAC"}
@@ -1,3 +0,0 @@
1
- import type { SimpleStreamOptions } from "@mupt-ai/pi-ai";
2
- import type { CreatePiRuntimeOptions, PiExecution, PiModel } from "./pi_types.js";
3
- export declare function piOptions(runtime: CreatePiRuntimeOptions, execution: PiExecution, model: PiModel): Promise<SimpleStreamOptions>;