@mono-agent/agent-runtime 0.15.4 → 0.16.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/MIGRATION.md +41 -13
- package/package.json +3 -3
- package/src/agent/tools/agent-tool.js +38 -3
- package/src/ai/pi-interop.js +7 -5
- package/src/ai/pi-oauth-compat.js +193 -0
- package/src/ai/providers/pi-native/turn-runner.js +13 -3
- package/src/ai/providers/pi-native.js +18 -2
- package/src/ai/runtime/router.js +10 -2
- package/src/ai/types.js +2 -1
- package/src/pi-auth.js +2 -2
- package/src/runtime.js +7 -0
- package/types/agent/tools/agent-tool.d.ts +21 -1
- package/types/ai/pi-oauth-compat.d.ts +57 -0
- package/types/ai/providers/pi-native/turn-runner.d.ts +2 -3
- package/types/ai/types.d.ts +11 -3
- package/types/ai/backend.d.ts +0 -57
- package/types/ai/registry.d.ts +0 -1
package/MIGRATION.md
CHANGED
|
@@ -42,8 +42,8 @@ the configuration schema.
|
|
|
42
42
|
switch to `listPiBuiltinModels`, `getPiBuiltinModel`,
|
|
43
43
|
`reasoningLevelsForPiModel`, `resolvePiOAuthApiKey`, and `loginPiOAuth` from
|
|
44
44
|
`@mono-agent/agent-runtime/ai`. The runtime keeps Pi AI and Pi Agent Core
|
|
45
|
-
exact-pinned at `0.
|
|
46
|
-
snapshots rather than exposing
|
|
45
|
+
exact-pinned at `0.83.0`; the façade returns cloned model and credential
|
|
46
|
+
snapshots rather than exposing upstream provider objects.
|
|
47
47
|
- **Claude test seam:** downstream tests should pass
|
|
48
48
|
`RuntimeRunOptions.claudeAgentQuery` instead of mocking
|
|
49
49
|
`@anthropic-ai/claude-agent-sdk` by package name. Normal runs omit this option
|
|
@@ -63,12 +63,27 @@ the configuration schema.
|
|
|
63
63
|
authoritative and the runtime emits a bounded
|
|
64
64
|
`live_input_callback_failed` warning.
|
|
65
65
|
|
|
66
|
-
## 0.
|
|
66
|
+
## 0.16.x baseline
|
|
67
67
|
|
|
68
68
|
This is the current published baseline for the detailed pre-1.0 reference
|
|
69
|
-
below. It
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
below. It carries the whole 0.15.x contract forward and adds:
|
|
70
|
+
|
|
71
|
+
- `skills` and `skillsRoot` on the run options. `skills` is the disclosed
|
|
72
|
+
`{name, description}` set for a run; a non-empty value makes `supports_skills`
|
|
73
|
+
a routing requirement, so a chain entry lacking it is skipped. `skillsRoot`
|
|
74
|
+
names the directory holding `<name>/SKILL.md` and is required alongside
|
|
75
|
+
`skills` for `ReadSkill` to exist. A subagent run now inherits both from its
|
|
76
|
+
parent unless a host-supplied `run` withholds them, so a child no longer has
|
|
77
|
+
to rediscover by trial and error what its parent could look up.
|
|
78
|
+
- Provider failover detail reaches whoever is watching the run rather than being
|
|
79
|
+
flattened at the boundary.
|
|
80
|
+
- Pi SDK 0.83.0.
|
|
81
|
+
|
|
82
|
+
## 0.15.x
|
|
83
|
+
|
|
84
|
+
- The explicit exports map, the five-bridge lazy registry, typed runtime
|
|
85
|
+
policies, runtime-owned provider dependencies, and the public-surface cleanup
|
|
86
|
+
described in this guide.
|
|
72
87
|
|
|
73
88
|
## 0.12.x
|
|
74
89
|
|
|
@@ -313,9 +328,22 @@ falls back to its own env vars, exactly as returning `undefined` from the old ho
|
|
|
313
328
|
did). **No host action needed** — `resolvePiApiKey` behaves as before.
|
|
314
329
|
|
|
315
330
|
Dependency bump: **`@earendil-works/pi-ai` and `@earendil-works/pi-agent-core` are
|
|
316
|
-
now `0.
|
|
317
|
-
`^0.79.1
|
|
318
|
-
|
|
331
|
+
now `0.83.0`** (the initial Pi 0.80 migration landed at `0.80.5`, from
|
|
332
|
+
`^0.79.1`, and ran at `0.80.6` until the 0.83 upgrade). Compaction is driven
|
|
333
|
+
natively (section 3), and model-native `max` reasoning plus Pi's request-wide
|
|
334
|
+
pricing tiers are preserved.
|
|
335
|
+
|
|
336
|
+
The 0.83 upgrade carries two upstream removals, both absorbed inside the runtime
|
|
337
|
+
so hosts need no action:
|
|
338
|
+
|
|
339
|
+
- `@earendil-works/pi-ai/oauth` became a type-only entry point. The generic
|
|
340
|
+
registry (`getOAuthApiKey`, `getOAuthProvider`, `getOAuthProviders`) is gone,
|
|
341
|
+
and the per-provider flows are not importable. `src/ai/pi-oauth-compat.js`
|
|
342
|
+
rebuilds the same contracts over `provider.auth.oauth`, so `resolvePiApiKey`,
|
|
343
|
+
`resolvePiOAuthApiKey`, and `loginPiOAuth` keep their existing signatures and
|
|
344
|
+
behaviour, including the refresh-on-expiry trigger.
|
|
345
|
+
- `AgentHarnessOptions.env` was removed in favour of a per-turn `toolContext`.
|
|
346
|
+
The runtime passes neither: it uses none of Pi's built-in file/shell tools.
|
|
319
347
|
|
|
320
348
|
### 11. Exports map: wildcards removed (explicit deep-path map)
|
|
321
349
|
|
|
@@ -366,7 +394,7 @@ a compatibility subpath.
|
|
|
366
394
|
|
|
367
395
|
## Version
|
|
368
396
|
|
|
369
|
-
This guide describes the published `0.
|
|
397
|
+
This guide describes the published `0.16.x` package contract. Keep
|
|
370
398
|
`@mono-agent/agent-runtime`, `@mono-agent/runtime-adapter`, and other
|
|
371
399
|
`@mono-agent/*` packages on the same lockstep version when upgrading. The paired
|
|
372
400
|
runtime adapter no longer exposes `piReasoningSummary` in its run-options type.
|
|
@@ -387,14 +415,14 @@ Worklab's runtime fork:
|
|
|
387
415
|
`@earendil-works/pi-ai`, its separate Pi version constraint, and local copies
|
|
388
416
|
of provider bridge code. Move tests off Pi's faux-provider helpers too; until
|
|
389
417
|
that is complete, isolate the fixture or pin its development-only Pi
|
|
390
|
-
dependency to exact `0.
|
|
418
|
+
dependency to exact `0.83.0` rather than a floating range. Do not restore the
|
|
391
419
|
removed `pi-sdk.js` subpath.
|
|
392
420
|
3. **Use the public Pi surfaces.** Run models through
|
|
393
421
|
`generatePiNativeResponse` or the runtime registry. Use
|
|
394
422
|
`listPiBuiltinModels`, `getPiBuiltinModel`,
|
|
395
423
|
`reasoningLevelsForPiModel`, `resolvePiOAuthApiKey`, and `loginPiOAuth` for
|
|
396
|
-
catalog and OAuth integration. Those façades keep Pi
|
|
397
|
-
exact `0.
|
|
424
|
+
catalog and OAuth integration. Those façades keep Pi provider objects and the
|
|
425
|
+
exact `0.83.0` compatibility pin inside the runtime. OAuth login adapters
|
|
398
426
|
must supply `onAuth`, `onDeviceCode`, `onPrompt`, and `onSelect`; the façade
|
|
399
427
|
rejects an incomplete callback contract before starting provider login.
|
|
400
428
|
4. **Inject Claude tests.** Replace package-level mocks of
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mono-agent/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Agent runtime supporting Claude SDK/CLI, Codex, OpenCode, and Pi SDK bridges out of the box",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "GPL-3.0-only",
|
|
@@ -133,8 +133,8 @@
|
|
|
133
133
|
"dependencies": {
|
|
134
134
|
"@anthropic-ai/claude-agent-sdk": "0.3.206",
|
|
135
135
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
136
|
-
"@earendil-works/pi-agent-core": "0.
|
|
137
|
-
"@earendil-works/pi-ai": "0.
|
|
136
|
+
"@earendil-works/pi-agent-core": "0.83.0",
|
|
137
|
+
"@earendil-works/pi-ai": "0.83.0",
|
|
138
138
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
139
139
|
"@mozilla/readability": "0.6.0",
|
|
140
140
|
"@opencode-ai/sdk": "^1.15.13",
|
|
@@ -93,12 +93,21 @@ function toolDescription(subagents, definitions, ceiling) {
|
|
|
93
93
|
const named = definitions.length === 0
|
|
94
94
|
? ""
|
|
95
95
|
: `\n\nAvailable subagents:\n${definitions.map((d) => `- ${d.name}: ${d.description}`).join("\n")}\n- ${GENERAL_PURPOSE_SUBAGENT}: read-only researcher inheriting the main model. Used when \`name\` is omitted.`;
|
|
96
|
+
// With authoring on, `name` is a free string rather than an enum, so it is
|
|
97
|
+
// the model's only signal for which of the two shapes it is writing. Left
|
|
98
|
+
// implicit, a caller that wants a configured profile AND a descriptive label
|
|
99
|
+
// splits those across two fields — label into `name`, profile into an
|
|
100
|
+
// invented one — and the closed schema rejects the whole call before any of
|
|
101
|
+
// the handler's precise errors can run.
|
|
102
|
+
const shapes = ceiling === null
|
|
103
|
+
? ""
|
|
104
|
+
: `\n\nExactly two ways to call this, and \`name\` carries the agent's identity in both:\n- Use a configured one: set \`name\` to a name from the list above. Nothing else.\n- Build one for this task: set \`name\` to a NEW kebab-case name AND \`systemPrompt\` to its full instructions (optionally \`tools\`, \`effort\`). Do that when no configured one fits — a dedicated prompt beats stuffing constraints into \`prompt\`.\n\n\`description\` is the short label shown in the activity log, never the agent's name. There is no separate field for choosing a configured agent.`;
|
|
96
105
|
// The ceiling is listed because the model has no other way to discover it: a
|
|
97
106
|
// tool it cannot see is indistinguishable from one it forgot to ask for.
|
|
98
107
|
const inline = ceiling === null
|
|
99
108
|
? ""
|
|
100
|
-
: `\n\
|
|
101
|
-
return `${DESCRIPTION_BASE}${parallel}${named}${inline}`;
|
|
109
|
+
: `\n\nTools you may grant a subagent you build: ${ceiling.join(", ")}. Anything else is dropped. Omit \`tools\` for a read-only helper.`;
|
|
110
|
+
return `${DESCRIPTION_BASE}${parallel}${named}${shapes}${inline}`;
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
/**
|
|
@@ -125,6 +134,27 @@ function budgetForRun(subagents, parentRunId) {
|
|
|
125
134
|
return fresh;
|
|
126
135
|
}
|
|
127
136
|
|
|
137
|
+
/**
|
|
138
|
+
* How many subagents this logical run actually spawned.
|
|
139
|
+
*
|
|
140
|
+
* A read-only accessor so a provider can report `subagent_invoked` truthfully
|
|
141
|
+
* without reaching into `__budgets`, which is a deliberately private,
|
|
142
|
+
* non-enumerable implementation detail. Returns 0 when nothing was ever
|
|
143
|
+
* registered — a run with no `Agent` tool never creates a budget entry, and that
|
|
144
|
+
* is indistinguishable from one that had the tool and never used it, which is
|
|
145
|
+
* exactly what "no subagent was invoked" means for this signal.
|
|
146
|
+
*
|
|
147
|
+
* @param {*} subagents The run-scoped options object, or undefined.
|
|
148
|
+
* @param {string|undefined} parentRunId
|
|
149
|
+
* @returns {number}
|
|
150
|
+
*/
|
|
151
|
+
export function subagentInvocationCount(subagents, parentRunId) {
|
|
152
|
+
const store = subagents?.__budgets;
|
|
153
|
+
if (!(store instanceof Map)) return 0;
|
|
154
|
+
const entry = store.get(parentRunId ?? "unkeyed");
|
|
155
|
+
return Number.isInteger(entry?.total) ? entry.total : 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
128
158
|
/** @param {*} value @param {number} fallback @returns {number} */
|
|
129
159
|
function positiveInt(value, fallback) {
|
|
130
160
|
return Number.isInteger(value) && value > 0 ? value : fallback;
|
|
@@ -134,7 +164,7 @@ function positiveInt(value, fallback) {
|
|
|
134
164
|
* Build the `Agent` tool, or null when subagents are unavailable for this run.
|
|
135
165
|
*
|
|
136
166
|
* @param {RuntimeSubagentsOptions|null|undefined} subagents
|
|
137
|
-
* @param {{model?: *, executionMode?: string, cwd?: string, parentRunId?: string, sandboxPolicy?: *, sandboxEngine?: *, onEvent?: (event: *) => void}} [context]
|
|
167
|
+
* @param {{model?: *, executionMode?: string, cwd?: string, parentRunId?: string, sandboxPolicy?: *, sandboxEngine?: *, skills?: {name: string, description?: string}[], skillsRoot?: string, onEvent?: (event: *) => void}} [context]
|
|
138
168
|
* @returns {*|null}
|
|
139
169
|
*/
|
|
140
170
|
export function createAgentTool(subagents, context = {}) {
|
|
@@ -326,6 +356,11 @@ export function createAgentTool(subagents, context = {}) {
|
|
|
326
356
|
// Inherited, never widened: a profile cannot loosen confinement.
|
|
327
357
|
...(context.sandboxPolicy === undefined ? {} : { sandboxPolicy: context.sandboxPolicy }),
|
|
328
358
|
...(context.sandboxEngine === undefined ? {} : { sandboxEngine: context.sandboxEngine }),
|
|
359
|
+
// The parent's disclosed skills. Offered, not imposed — the host's
|
|
360
|
+
// `run` decides whether this child may have them, since only it knows
|
|
361
|
+
// the child's resolved route and deny lists.
|
|
362
|
+
...(context.skills === undefined ? {} : { skills: context.skills }),
|
|
363
|
+
...(context.skillsRoot === undefined ? {} : { skillsRoot: context.skillsRoot }),
|
|
329
364
|
abortSignal: controller.signal,
|
|
330
365
|
maxTurns,
|
|
331
366
|
callId: toolCallId,
|
package/src/ai/pi-interop.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// directly so the runtime's known-good Pi version remains authoritative.
|
|
4
4
|
|
|
5
5
|
import { getBuiltinModel, getBuiltinModels } from "@earendil-works/pi-ai/providers/all";
|
|
6
|
-
import {
|
|
6
|
+
import { getPiOAuthAuth, resolveOAuthApiKey, toAuthInteraction } from "./pi-oauth-compat.js";
|
|
7
7
|
import { reasoningLevelsForPiModel as resolveReasoningLevels } from "./providers/pi-models.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -122,7 +122,7 @@ export function reasoningLevelsForPiModel(model) {
|
|
|
122
122
|
* @returns {Promise<{apiKey: string, newCredentials: PiOAuthCredentialsSnapshot}|null>}
|
|
123
123
|
*/
|
|
124
124
|
export async function resolvePiOAuthApiKey(providerId, credentials) {
|
|
125
|
-
const result = await
|
|
125
|
+
const result = await resolveOAuthApiKey(
|
|
126
126
|
providerId,
|
|
127
127
|
/** @type {any} */ (cloneInteropValue(credentials)),
|
|
128
128
|
);
|
|
@@ -142,8 +142,8 @@ export async function resolvePiOAuthApiKey(providerId, credentials) {
|
|
|
142
142
|
* @returns {Promise<PiOAuthCredentialsSnapshot>}
|
|
143
143
|
*/
|
|
144
144
|
export async function loginPiOAuth(providerId, callbacks) {
|
|
145
|
-
const
|
|
146
|
-
if (!
|
|
145
|
+
const oauth = getPiOAuthAuth(providerId);
|
|
146
|
+
if (!oauth || typeof oauth.login !== "function") {
|
|
147
147
|
throw new Error(`Pi OAuth provider is unavailable: ${providerId}`);
|
|
148
148
|
}
|
|
149
149
|
for (const callbackName of ["onAuth", "onDeviceCode", "onPrompt", "onSelect"]) {
|
|
@@ -151,6 +151,8 @@ export async function loginPiOAuth(providerId, callbacks) {
|
|
|
151
151
|
throw new TypeError(`loginPiOAuth requires callbacks.${callbackName}()`);
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
const credentials = await
|
|
154
|
+
const credentials = await oauth.login(
|
|
155
|
+
toAuthInteraction(/** @type {any} */ ({ ...callbacks })),
|
|
156
|
+
);
|
|
155
157
|
return cloneInteropValue(credentials);
|
|
156
158
|
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
// Adapter over pi-ai's provider-owned OAuth surface.
|
|
4
|
+
//
|
|
5
|
+
// pi-ai 0.83.0 removed the generic OAuth registry — `getOAuthApiKey`,
|
|
6
|
+
// `getOAuthProvider` and `getOAuthProviders` are gone, and the
|
|
7
|
+
// `@earendil-works/pi-ai/oauth` entry point is now type-only (`export {}` at
|
|
8
|
+
// runtime). The per-provider implementations (`anthropicOAuth`, …) live under
|
|
9
|
+
// `dist/auth/oauth/*`, which has no entry in the package's `exports` map, so
|
|
10
|
+
// they cannot be imported. The supported surface is `provider.auth.oauth`,
|
|
11
|
+
// reached through the provider factories.
|
|
12
|
+
//
|
|
13
|
+
// mono-agent resolves providers dynamically from `pi:<provider>:<model>`, so it
|
|
14
|
+
// needs a lookup by id — this module rebuilds that over `builtinProviders()` and
|
|
15
|
+
// preserves the old call contracts exactly, keeping the migration confined here.
|
|
16
|
+
//
|
|
17
|
+
// Deliberately NOT using `createModels({credentials})`: that hands credential
|
|
18
|
+
// locking and persistence to pi, while mono-agent already owns `auth.json`
|
|
19
|
+
// through `pi-auth.js` (serialized writes, atomic 0600 rename). `refresh()` and
|
|
20
|
+
// `toAuth()` are callable directly, so the pure caller-persists contract stays.
|
|
21
|
+
|
|
22
|
+
import { builtinProviders } from "@earendil-works/pi-ai/providers/all";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {import("@earendil-works/pi-ai").OAuthAuth} OAuthAuth
|
|
26
|
+
* @typedef {import("@earendil-works/pi-ai").OAuthCredential} OAuthCredential
|
|
27
|
+
* @typedef {import("@earendil-works/pi-ai").AuthInteraction} AuthInteraction
|
|
28
|
+
* @typedef {import("@earendil-works/pi-ai").AuthPrompt} AuthPrompt
|
|
29
|
+
* @typedef {import("@earendil-works/pi-ai").AuthEvent} AuthEvent
|
|
30
|
+
* @typedef {import("@earendil-works/pi-ai/oauth").OAuthLoginCallbacks} OAuthLoginCallbacks
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** @type {Map<string, import("@earendil-works/pi-ai").Provider>|undefined} */
|
|
34
|
+
let providerIndexCache;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `builtinProviders()` freshly constructs every provider (~37 objects) on each
|
|
38
|
+
* call, and `pi-auth.js` sits on the per-request credential path. The catalog is
|
|
39
|
+
* static for the process lifetime, so index it once.
|
|
40
|
+
*
|
|
41
|
+
* @returns {Map<string, import("@earendil-works/pi-ai").Provider>}
|
|
42
|
+
*/
|
|
43
|
+
function providerIndex() {
|
|
44
|
+
if (providerIndexCache === undefined) {
|
|
45
|
+
providerIndexCache = new Map(builtinProviders().map((provider) => [provider.id, provider]));
|
|
46
|
+
}
|
|
47
|
+
return providerIndexCache;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @internal Exported only so tests can force a rebuild of the memoized index. */
|
|
51
|
+
export function resetPiProviderIndexForTests() {
|
|
52
|
+
providerIndexCache = undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The OAuth implementation for a Pi provider id, or undefined when the provider
|
|
57
|
+
* is unknown or supports only API-key auth (e.g. `opencode-go`).
|
|
58
|
+
*
|
|
59
|
+
* @param {string} providerId
|
|
60
|
+
* @returns {OAuthAuth|undefined}
|
|
61
|
+
*/
|
|
62
|
+
export function getPiOAuthAuth(providerId) {
|
|
63
|
+
if (typeof providerId !== "string" || providerId.length === 0) return undefined;
|
|
64
|
+
return providerIndex().get(providerId)?.auth?.oauth;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Every Pi provider id that supports OAuth. Replaces
|
|
69
|
+
* `getOAuthProviders().map((provider) => provider.id)`.
|
|
70
|
+
*
|
|
71
|
+
* @returns {string[]}
|
|
72
|
+
*/
|
|
73
|
+
export function getPiOAuthProviderIds() {
|
|
74
|
+
const ids = [];
|
|
75
|
+
for (const [id, provider] of providerIndex()) {
|
|
76
|
+
if (provider.auth?.oauth !== undefined) ids.push(id);
|
|
77
|
+
}
|
|
78
|
+
return ids;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolve an API key from stored OAuth credentials, refreshing first when the
|
|
83
|
+
* token has expired.
|
|
84
|
+
*
|
|
85
|
+
* Reproduces pi-ai 0.80.6's `getOAuthApiKey(providerId, credentials)` contract
|
|
86
|
+
* so its call sites keep their shape: takes the whole provider-keyed credential
|
|
87
|
+
* map, returns `null` when this provider has no stored credential, and is
|
|
88
|
+
* *pure* — the refreshed credential comes back as `newCredentials` for the
|
|
89
|
+
* caller to persist rather than being written here.
|
|
90
|
+
*
|
|
91
|
+
* The refresh trigger is deliberately the old exact-expiry check. pi's own
|
|
92
|
+
* `Models.getAuth()` refreshes five minutes ahead of expiry; matching that would
|
|
93
|
+
* change live token rotation timing, which this migration does not intend.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} providerId
|
|
96
|
+
* @param {Record<string, *>|undefined} credentials Provider-keyed credential map.
|
|
97
|
+
* @returns {Promise<{newCredentials: OAuthCredential, apiKey: string|undefined}|null>}
|
|
98
|
+
*/
|
|
99
|
+
export async function resolveOAuthApiKey(providerId, credentials) {
|
|
100
|
+
const oauth = getPiOAuthAuth(providerId);
|
|
101
|
+
if (oauth === undefined) {
|
|
102
|
+
throw new Error(`Unknown OAuth provider: ${providerId}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const stored = credentials?.[providerId];
|
|
106
|
+
if (stored === undefined || stored === null) return null;
|
|
107
|
+
|
|
108
|
+
// 0.83.0's OAuthCredential carries a `type: "oauth"` discriminant that the
|
|
109
|
+
// 0.80.6 shape did not. Stored entries written by mono-agent already have it;
|
|
110
|
+
// tag defensively so hand-edited or externally written files still work.
|
|
111
|
+
let credential = /** @type {OAuthCredential} */ ({ ...stored, type: "oauth" });
|
|
112
|
+
|
|
113
|
+
if (Date.now() >= credential.expires) {
|
|
114
|
+
try {
|
|
115
|
+
credential = await oauth.refresh(credential);
|
|
116
|
+
} catch {
|
|
117
|
+
throw new Error(`Failed to refresh OAuth token for ${providerId}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// `toAuth()` also derives a per-credential baseUrl (GitHub Copilot's
|
|
122
|
+
// per-account proxy). 0.80.6 discarded it and callers here have no field for
|
|
123
|
+
// it, so it stays dropped — behaviour preserved, worth revisiting separately.
|
|
124
|
+
const auth = await oauth.toAuth(credential);
|
|
125
|
+
return { newCredentials: credential, apiKey: auth?.apiKey };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Bridge the legacy six-callback OAuth surface onto 0.83.0's single
|
|
130
|
+
* `prompt`/`notify` pair.
|
|
131
|
+
*
|
|
132
|
+
* `manual_code` must stay wired to `onManualCodeInput`: Anthropic races its
|
|
133
|
+
* localhost callback against a pasted redirect URL, and that path is the reason
|
|
134
|
+
* `agent-app`'s `runPiOAuthLogin` exists at all.
|
|
135
|
+
*
|
|
136
|
+
* @param {OAuthLoginCallbacks} callbacks
|
|
137
|
+
* @returns {AuthInteraction}
|
|
138
|
+
*/
|
|
139
|
+
export function toAuthInteraction(callbacks) {
|
|
140
|
+
if (callbacks === null || typeof callbacks !== "object") {
|
|
141
|
+
throw new TypeError("toAuthInteraction requires an OAuthLoginCallbacks object");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
...(callbacks.signal === undefined ? {} : { signal: callbacks.signal }),
|
|
146
|
+
|
|
147
|
+
/** @param {AuthPrompt} prompt */
|
|
148
|
+
async prompt(prompt) {
|
|
149
|
+
if (prompt.type === "select") {
|
|
150
|
+
const selected = await callbacks.onSelect({
|
|
151
|
+
message: prompt.message,
|
|
152
|
+
options: prompt.options.map((option) => ({ id: option.id, label: option.label })),
|
|
153
|
+
});
|
|
154
|
+
// The legacy callback resolves undefined when the user cancels; the new
|
|
155
|
+
// contract requires a string and rejects on cancel.
|
|
156
|
+
if (typeof selected !== "string") {
|
|
157
|
+
throw new Error("OAuth provider selection was cancelled.");
|
|
158
|
+
}
|
|
159
|
+
return selected;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (prompt.type === "manual_code" && typeof callbacks.onManualCodeInput === "function") {
|
|
163
|
+
return await callbacks.onManualCodeInput();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return await callbacks.onPrompt({
|
|
167
|
+
message: prompt.message,
|
|
168
|
+
...(prompt.placeholder === undefined ? {} : { placeholder: prompt.placeholder }),
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/** @param {AuthEvent} event */
|
|
173
|
+
notify(event) {
|
|
174
|
+
if (event.type === "auth_url") {
|
|
175
|
+
callbacks.onAuth({
|
|
176
|
+
url: event.url,
|
|
177
|
+
...(event.instructions === undefined ? {} : { instructions: event.instructions }),
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (event.type === "device_code") {
|
|
182
|
+
callbacks.onDeviceCode({
|
|
183
|
+
userCode: event.userCode,
|
|
184
|
+
verificationUri: event.verificationUri,
|
|
185
|
+
...(event.intervalSeconds === undefined ? {} : { intervalSeconds: event.intervalSeconds }),
|
|
186
|
+
...(event.expiresInSeconds === undefined ? {} : { expiresInSeconds: event.expiresInSeconds }),
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
callbacks.onProgress?.(event.message);
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
// caller-owned runState.
|
|
9
9
|
|
|
10
10
|
import { AgentHarness } from "@earendil-works/pi-agent-core";
|
|
11
|
-
import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node";
|
|
12
11
|
import {
|
|
13
12
|
createStructuredOutputTool,
|
|
14
13
|
getPiBuiltinTools,
|
|
@@ -134,6 +133,14 @@ export async function buildTurnTools(runState, {
|
|
|
134
133
|
// child is never less sandboxed than the parent that spawned it.
|
|
135
134
|
sandboxPolicy: options.sandboxPolicy,
|
|
136
135
|
sandboxEngine,
|
|
136
|
+
// The same skills this turn was disclosed. A child runs OUTSIDE the
|
|
137
|
+
// harness, so without this it gets no index and — because ReadSkill is
|
|
138
|
+
// only built when `skills` is non-empty — no way to read one either. It
|
|
139
|
+
// then rediscovers by trial and error whatever its parent could simply
|
|
140
|
+
// have looked up. Pass-through only: whether the child actually receives
|
|
141
|
+
// them is the host's decision, not this layer's.
|
|
142
|
+
skills: options.skills,
|
|
143
|
+
skillsRoot: options.skillsRoot,
|
|
137
144
|
},
|
|
138
145
|
ctx: runCtx,
|
|
139
146
|
}));
|
|
@@ -241,7 +248,6 @@ export function toolResultErrorOverride(details) {
|
|
|
241
248
|
}
|
|
242
249
|
|
|
243
250
|
export function buildTurnHarness(runState, {
|
|
244
|
-
cwd,
|
|
245
251
|
session,
|
|
246
252
|
piModels,
|
|
247
253
|
model,
|
|
@@ -259,8 +265,12 @@ export function buildTurnHarness(runState, {
|
|
|
259
265
|
sdk,
|
|
260
266
|
reference,
|
|
261
267
|
}) {
|
|
268
|
+
// pi-agent-core 0.83.0 removed `env` from AgentHarnessOptions: an
|
|
269
|
+
// ExecutionEnv now reaches tools through the generic per-turn `toolContext`
|
|
270
|
+
// instead. mono-agent needs neither — it uses none of pi's built-in
|
|
271
|
+
// file/shell tools, and its own tools close over what they need — so the
|
|
272
|
+
// option is dropped rather than migrated.
|
|
262
273
|
const harness = new AgentHarness({
|
|
263
|
-
env: new NodeExecutionEnv({ cwd: cwd || process.cwd() }),
|
|
264
274
|
session,
|
|
265
275
|
models: piModels,
|
|
266
276
|
model,
|
|
@@ -31,7 +31,9 @@ import {
|
|
|
31
31
|
resolveAgentCompactionPolicy,
|
|
32
32
|
resolveRuntimePolicyInputs,
|
|
33
33
|
} from "../../agent/compaction.js";
|
|
34
|
+
import { subagentInvocationCount } from "../../agent/tools/agent-tool.js";
|
|
34
35
|
import { closePiMcpClients } from "../../agent/tools/pi-bridge.js";
|
|
36
|
+
import { readToolRuntime } from "../../agent/tools/shared/runtime-context.js";
|
|
35
37
|
import { createApprovalManager } from "../../agent/approval.js";
|
|
36
38
|
import { buildCapabilitiesUsed, toolCompactionAppliedFromWarnings } from "../runtime/capabilities-used.js";
|
|
37
39
|
import { reasoningLevelsForPiModel, resolvePiRuntimeModel } from "./pi-models.js";
|
|
@@ -481,7 +483,6 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
|
|
|
481
483
|
// external abort handler (which sets runState.externalAbort and aborts the
|
|
482
484
|
// harness). Sets runState.harness + runState.removeAbortHandler.
|
|
483
485
|
harness = buildTurnHarness(runState, {
|
|
484
|
-
cwd: options.cwd,
|
|
485
486
|
session: runState.session,
|
|
486
487
|
piModels,
|
|
487
488
|
model: runtime.model,
|
|
@@ -709,8 +710,23 @@ export async function generatePiNativeResponse(systemPrompt, options = {}) {
|
|
|
709
710
|
promptCacheActive: usage.cacheRead > 0 || usage.cacheWrite > 0,
|
|
710
711
|
thinkingEnabled: effectiveThinkingLevel !== "off" && effectiveThinkingLevel !== "low",
|
|
711
712
|
structuredOutputEnforced: !!options.outputSchema,
|
|
712
|
-
|
|
713
|
+
// What actually happened, not what was configured. This used to be a
|
|
714
|
+
// hardcoded `false`, which reported "no subagent ran" for runs that had
|
|
715
|
+
// just spawned several — the one signal that would have shown delegation
|
|
716
|
+
// working said it never happened.
|
|
717
|
+
//
|
|
718
|
+
// The count is keyed by the same parentRunId the Agent tool stamps its
|
|
719
|
+
// budget under (turn-runner threads `runCtx?.runId`); `runId` survives the
|
|
720
|
+
// sandbox-branch spread there, so reading it off the tool context directly
|
|
721
|
+
// yields the same key.
|
|
722
|
+
subagentInvoked: subagentInvocationCount(
|
|
723
|
+
options.subagents,
|
|
724
|
+
(options.toolContext ?? readToolRuntime())?.runId,
|
|
725
|
+
) > 0,
|
|
713
726
|
mcpServersUsed: mcpClients.map((entry) => entry?.name).filter(Boolean),
|
|
727
|
+
// Empty by contract, not by omission: "native" means provider-native
|
|
728
|
+
// subagents (Claude's Task tool). mono-agent's `Agent` is its own, so pi
|
|
729
|
+
// has none — `subagent_invoked` above is where pi delegation is reported.
|
|
714
730
|
nativeSubagentsUsed: [],
|
|
715
731
|
toolCompactionApplied: toolCompactionAppliedFromWarnings(runtimeWarnings),
|
|
716
732
|
// Tristate: true = a compaction fired this run (proactive or reactive),
|
package/src/ai/runtime/router.js
CHANGED
|
@@ -335,11 +335,16 @@ export function createRouterRuntime({ host = {}, chain = [], routeSafety = "unif
|
|
|
335
335
|
// A same-model retry is not a failover: only the first attempt of a new
|
|
336
336
|
// route announces a transition.
|
|
337
337
|
if (retryIndex === 0 && failoverHistory.length > 0) {
|
|
338
|
+
const previous = failoverHistory[failoverHistory.length - 1];
|
|
338
339
|
emit(callOptions, {
|
|
339
340
|
type: "provider_failover_started",
|
|
340
|
-
from: modelKey(
|
|
341
|
+
from: modelKey(previous?.model),
|
|
341
342
|
to: modelKey(entry.model),
|
|
342
343
|
attemptIndex: i,
|
|
344
|
+
// Why the route changed, in the same vocabulary provider_retry_started
|
|
345
|
+
// uses. Operators reading a transcript need the cause next to the
|
|
346
|
+
// transition, not only in the run artifact's failoverHistory.
|
|
347
|
+
reason: previous?.retryableSubkind || previous?.failureKind || null,
|
|
343
348
|
});
|
|
344
349
|
}
|
|
345
350
|
|
|
@@ -378,9 +383,12 @@ export function createRouterRuntime({ host = {}, chain = [], routeSafety = "unif
|
|
|
378
383
|
// (failover)" when X is still the route the operator asked for.
|
|
379
384
|
if (failoverHistory.some((attempt) => modelKey(attempt.model) !== modelKey(entry.model))) {
|
|
380
385
|
emit(callOptions, {
|
|
386
|
+
// modelKey, not the ModelRef: every consumer of this event reads
|
|
387
|
+
// `model` as a string (responder.ts's stringField is string-only),
|
|
388
|
+
// so an object here is dropped silently rather than rendered.
|
|
381
389
|
type: "provider_failover_completed",
|
|
382
390
|
attemptIndex: i,
|
|
383
|
-
model: entry.model,
|
|
391
|
+
model: modelKey(entry.model),
|
|
384
392
|
});
|
|
385
393
|
}
|
|
386
394
|
return { ...result, failoverHistory, routeSafetyHistory };
|
package/src/ai/types.js
CHANGED
|
@@ -147,7 +147,8 @@
|
|
|
147
147
|
* @property {boolean} [fastMode]
|
|
148
148
|
* @property {string} [cwd]
|
|
149
149
|
* @property {Object<string, Object>} [mcpServers]
|
|
150
|
-
* @property {ReadonlyArray<
|
|
150
|
+
* @property {ReadonlyArray<{name: string, description?: string}>} [skills] Skills disclosed to this run, as `{name, description}`. Non-empty makes `supports_skills` a routing requirement (see router.js), so a chain entry that lacks it is skipped.
|
|
151
|
+
* @property {string} [skillsRoot] Directory holding `<name>/SKILL.md`. Required alongside `skills` for `ReadSkill` to be built.
|
|
151
152
|
* @property {ReadonlyArray<string>} [allowedTools]
|
|
152
153
|
* @property {ReadonlyArray<string>} [disallowedTools]
|
|
153
154
|
* @property {string} [permissionMode]
|
package/src/pi-auth.js
CHANGED
|
@@ -4,7 +4,7 @@ import { realpathSync } from "node:fs";
|
|
|
4
4
|
import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
5
5
|
import { basename, dirname, join, resolve } from "node:path";
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { resolveOAuthApiKey } from "./ai/pi-oauth-compat.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {{type: "api_key", key?: string, env?: Object<string, *>}} PiApiKeyCredential
|
|
@@ -41,7 +41,7 @@ export function createPiOAuthApiKeyResolver(options = {}) {
|
|
|
41
41
|
return undefined;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const result = await
|
|
44
|
+
const result = await resolveOAuthApiKey(provider, cloneAuth(auth));
|
|
45
45
|
if (result === null || result === undefined || typeof result.apiKey !== "string" || result.apiKey.length === 0) {
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
package/src/runtime.js
CHANGED
|
@@ -165,6 +165,13 @@ export function createRuntime(host = {}) {
|
|
|
165
165
|
// WebSearch, so even a read-only profile could bypass network policy.
|
|
166
166
|
...(request.sandboxPolicy === undefined ? {} : { sandboxPolicy: request.sandboxPolicy }),
|
|
167
167
|
...(request.sandboxEngine === undefined ? {} : { sandboxEngine: request.sandboxEngine }),
|
|
168
|
+
// The parent's disclosed skills, for the same reason: they are a per-run
|
|
169
|
+
// option, so a child that does not receive them has no ReadSkill tool and no
|
|
170
|
+
// index, and must rediscover by trial and error what its parent could look
|
|
171
|
+
// up. A host-supplied `run` may gate this; the default has no route or deny
|
|
172
|
+
// list of its own to consult, so it forwards what it was given.
|
|
173
|
+
...(request.skills === undefined ? {} : { skills: request.skills }),
|
|
174
|
+
...(request.skillsRoot === undefined ? {} : { skillsRoot: request.skillsRoot }),
|
|
168
175
|
...(request.executionMode === undefined ? {} : { executionMode: request.executionMode }),
|
|
169
176
|
...(request.cwd === undefined ? {} : { cwd: request.cwd }),
|
|
170
177
|
// A profile that pins effort — declared or authored at call time — means it
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many subagents this logical run actually spawned.
|
|
3
|
+
*
|
|
4
|
+
* A read-only accessor so a provider can report `subagent_invoked` truthfully
|
|
5
|
+
* without reaching into `__budgets`, which is a deliberately private,
|
|
6
|
+
* non-enumerable implementation detail. Returns 0 when nothing was ever
|
|
7
|
+
* registered — a run with no `Agent` tool never creates a budget entry, and that
|
|
8
|
+
* is indistinguishable from one that had the tool and never used it, which is
|
|
9
|
+
* exactly what "no subagent was invoked" means for this signal.
|
|
10
|
+
*
|
|
11
|
+
* @param {*} subagents The run-scoped options object, or undefined.
|
|
12
|
+
* @param {string|undefined} parentRunId
|
|
13
|
+
* @returns {number}
|
|
14
|
+
*/
|
|
15
|
+
export function subagentInvocationCount(subagents: any, parentRunId: string | undefined): number;
|
|
1
16
|
/**
|
|
2
17
|
* Build the `Agent` tool, or null when subagents are unavailable for this run.
|
|
3
18
|
*
|
|
4
19
|
* @param {RuntimeSubagentsOptions|null|undefined} subagents
|
|
5
|
-
* @param {{model?: *, executionMode?: string, cwd?: string, parentRunId?: string, sandboxPolicy?: *, sandboxEngine?: *, onEvent?: (event: *) => void}} [context]
|
|
20
|
+
* @param {{model?: *, executionMode?: string, cwd?: string, parentRunId?: string, sandboxPolicy?: *, sandboxEngine?: *, skills?: {name: string, description?: string}[], skillsRoot?: string, onEvent?: (event: *) => void}} [context]
|
|
6
21
|
* @returns {*|null}
|
|
7
22
|
*/
|
|
8
23
|
export function createAgentTool(subagents: RuntimeSubagentsOptions | null | undefined, context?: {
|
|
@@ -12,6 +27,11 @@ export function createAgentTool(subagents: RuntimeSubagentsOptions | null | unde
|
|
|
12
27
|
parentRunId?: string;
|
|
13
28
|
sandboxPolicy?: any;
|
|
14
29
|
sandboxEngine?: any;
|
|
30
|
+
skills?: {
|
|
31
|
+
name: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}[];
|
|
34
|
+
skillsRoot?: string;
|
|
15
35
|
onEvent?: (event: any) => void;
|
|
16
36
|
}): any | null;
|
|
17
37
|
/**
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** @internal Exported only so tests can force a rebuild of the memoized index. */
|
|
2
|
+
export function resetPiProviderIndexForTests(): void;
|
|
3
|
+
/**
|
|
4
|
+
* The OAuth implementation for a Pi provider id, or undefined when the provider
|
|
5
|
+
* is unknown or supports only API-key auth (e.g. `opencode-go`).
|
|
6
|
+
*
|
|
7
|
+
* @param {string} providerId
|
|
8
|
+
* @returns {OAuthAuth|undefined}
|
|
9
|
+
*/
|
|
10
|
+
export function getPiOAuthAuth(providerId: string): OAuthAuth | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Every Pi provider id that supports OAuth. Replaces
|
|
13
|
+
* `getOAuthProviders().map((provider) => provider.id)`.
|
|
14
|
+
*
|
|
15
|
+
* @returns {string[]}
|
|
16
|
+
*/
|
|
17
|
+
export function getPiOAuthProviderIds(): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Resolve an API key from stored OAuth credentials, refreshing first when the
|
|
20
|
+
* token has expired.
|
|
21
|
+
*
|
|
22
|
+
* Reproduces pi-ai 0.80.6's `getOAuthApiKey(providerId, credentials)` contract
|
|
23
|
+
* so its call sites keep their shape: takes the whole provider-keyed credential
|
|
24
|
+
* map, returns `null` when this provider has no stored credential, and is
|
|
25
|
+
* *pure* — the refreshed credential comes back as `newCredentials` for the
|
|
26
|
+
* caller to persist rather than being written here.
|
|
27
|
+
*
|
|
28
|
+
* The refresh trigger is deliberately the old exact-expiry check. pi's own
|
|
29
|
+
* `Models.getAuth()` refreshes five minutes ahead of expiry; matching that would
|
|
30
|
+
* change live token rotation timing, which this migration does not intend.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} providerId
|
|
33
|
+
* @param {Record<string, *>|undefined} credentials Provider-keyed credential map.
|
|
34
|
+
* @returns {Promise<{newCredentials: OAuthCredential, apiKey: string|undefined}|null>}
|
|
35
|
+
*/
|
|
36
|
+
export function resolveOAuthApiKey(providerId: string, credentials: Record<string, any> | undefined): Promise<{
|
|
37
|
+
newCredentials: OAuthCredential;
|
|
38
|
+
apiKey: string | undefined;
|
|
39
|
+
} | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Bridge the legacy six-callback OAuth surface onto 0.83.0's single
|
|
42
|
+
* `prompt`/`notify` pair.
|
|
43
|
+
*
|
|
44
|
+
* `manual_code` must stay wired to `onManualCodeInput`: Anthropic races its
|
|
45
|
+
* localhost callback against a pasted redirect URL, and that path is the reason
|
|
46
|
+
* `agent-app`'s `runPiOAuthLogin` exists at all.
|
|
47
|
+
*
|
|
48
|
+
* @param {OAuthLoginCallbacks} callbacks
|
|
49
|
+
* @returns {AuthInteraction}
|
|
50
|
+
*/
|
|
51
|
+
export function toAuthInteraction(callbacks: OAuthLoginCallbacks): AuthInteraction;
|
|
52
|
+
export type OAuthAuth = import("@earendil-works/pi-ai").OAuthAuth;
|
|
53
|
+
export type OAuthCredential = import("@earendil-works/pi-ai").OAuthCredential;
|
|
54
|
+
export type AuthInteraction = import("@earendil-works/pi-ai").AuthInteraction;
|
|
55
|
+
export type AuthPrompt = import("@earendil-works/pi-ai").AuthPrompt;
|
|
56
|
+
export type AuthEvent = import("@earendil-works/pi-ai").AuthEvent;
|
|
57
|
+
export type OAuthLoginCallbacks = import("@earendil-works/pi-ai/oauth").OAuthLoginCallbacks;
|
|
@@ -45,8 +45,7 @@ export function thinkingLevelForEffort(effort: string, capabilities: any): strin
|
|
|
45
45
|
export function toolResultErrorOverride(details: any): {
|
|
46
46
|
isError: true;
|
|
47
47
|
} | undefined;
|
|
48
|
-
export function buildTurnHarness(runState: any, {
|
|
49
|
-
cwd: any;
|
|
48
|
+
export function buildTurnHarness(runState: any, { session, piModels, model, thinkingLevel, systemPrompt, outputSchema, tools, transport, maxRetries, maxRetryDelayMs, steeringMode, onEvent, options, toolLimits, sdk, reference, }: {
|
|
50
49
|
session: any;
|
|
51
50
|
piModels: any;
|
|
52
51
|
model: any;
|
|
@@ -63,7 +62,7 @@ export function buildTurnHarness(runState: any, { cwd, session, piModels, model,
|
|
|
63
62
|
toolLimits: any;
|
|
64
63
|
sdk: any;
|
|
65
64
|
reference: any;
|
|
66
|
-
}): AgentHarness<import("@earendil-works/pi-agent-core").Skill, import("@earendil-works/pi-agent-core").PromptTemplate, import("@earendil-works/pi-agent-core").
|
|
65
|
+
}): AgentHarness<undefined, import("@earendil-works/pi-agent-core").Skill, import("@earendil-works/pi-agent-core").PromptTemplate, import("@earendil-works/pi-agent-core").AgentHarnessTool<undefined>>;
|
|
67
66
|
/**
|
|
68
67
|
* Start the live-input steering consumer. Consumes follow-up messages and steers
|
|
69
68
|
* the harness mid-run; the consumer is tied to run completion (an internal
|
package/types/ai/types.d.ts
CHANGED
|
@@ -118,7 +118,8 @@
|
|
|
118
118
|
* @property {boolean} [fastMode]
|
|
119
119
|
* @property {string} [cwd]
|
|
120
120
|
* @property {Object<string, Object>} [mcpServers]
|
|
121
|
-
* @property {ReadonlyArray<
|
|
121
|
+
* @property {ReadonlyArray<{name: string, description?: string}>} [skills] Skills disclosed to this run, as `{name, description}`. Non-empty makes `supports_skills` a routing requirement (see router.js), so a chain entry that lacks it is skipped.
|
|
122
|
+
* @property {string} [skillsRoot] Directory holding `<name>/SKILL.md`. Required alongside `skills` for `ReadSkill` to be built.
|
|
122
123
|
* @property {ReadonlyArray<string>} [allowedTools]
|
|
123
124
|
* @property {ReadonlyArray<string>} [disallowedTools]
|
|
124
125
|
* @property {string} [permissionMode]
|
|
@@ -578,9 +579,16 @@ export type RuntimeRunOptions = {
|
|
|
578
579
|
[x: string]: any;
|
|
579
580
|
};
|
|
580
581
|
/**
|
|
581
|
-
*
|
|
582
|
+
* Skills disclosed to this run, as `{name, description}`. Non-empty makes `supports_skills` a routing requirement (see router.js), so a chain entry that lacks it is skipped.
|
|
582
583
|
*/
|
|
583
|
-
skills?: ReadonlyArray<
|
|
584
|
+
skills?: ReadonlyArray<{
|
|
585
|
+
name: string;
|
|
586
|
+
description?: string;
|
|
587
|
+
}>;
|
|
588
|
+
/**
|
|
589
|
+
* Directory holding `<name>/SKILL.md`. Required alongside `skills` for `ReadSkill` to be built.
|
|
590
|
+
*/
|
|
591
|
+
skillsRoot?: string;
|
|
584
592
|
allowedTools?: ReadonlyArray<string>;
|
|
585
593
|
disallowedTools?: ReadonlyArray<string>;
|
|
586
594
|
permissionMode?: string;
|
package/types/ai/backend.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
export function backendCapabilities(sdkOrModel: any): any;
|
|
2
|
-
export function backendUsesExecenvConfig(sdk: any): boolean;
|
|
3
|
-
export function backendSupportsSessionResume(sdk: any): boolean;
|
|
4
|
-
export const BACKEND_CAPABILITIES: {
|
|
5
|
-
claude: {
|
|
6
|
-
supports_session_resume: boolean;
|
|
7
|
-
streaming: boolean;
|
|
8
|
-
structured_output: boolean;
|
|
9
|
-
native_runtime_config: any;
|
|
10
|
-
supports_mcp: boolean;
|
|
11
|
-
supports_skills: boolean;
|
|
12
|
-
supports_builtin_tools: boolean;
|
|
13
|
-
supports_live_input: boolean;
|
|
14
|
-
supports_native_subagents: boolean;
|
|
15
|
-
supports_fast_mode: boolean;
|
|
16
|
-
runtime: string;
|
|
17
|
-
};
|
|
18
|
-
pi: {
|
|
19
|
-
supports_session_resume: boolean;
|
|
20
|
-
supports_native_subagents: boolean;
|
|
21
|
-
streaming: boolean;
|
|
22
|
-
structured_output: boolean;
|
|
23
|
-
native_runtime_config: any;
|
|
24
|
-
supports_mcp: boolean;
|
|
25
|
-
supports_skills: boolean;
|
|
26
|
-
supports_builtin_tools: boolean;
|
|
27
|
-
supports_live_input: boolean;
|
|
28
|
-
supports_fast_mode: boolean;
|
|
29
|
-
runtime: string;
|
|
30
|
-
};
|
|
31
|
-
codex: {
|
|
32
|
-
supports_session_resume: boolean;
|
|
33
|
-
supports_fast_mode: boolean;
|
|
34
|
-
streaming: boolean;
|
|
35
|
-
structured_output: boolean;
|
|
36
|
-
native_runtime_config: any;
|
|
37
|
-
supports_mcp: boolean;
|
|
38
|
-
supports_skills: boolean;
|
|
39
|
-
supports_builtin_tools: boolean;
|
|
40
|
-
supports_live_input: boolean;
|
|
41
|
-
supports_native_subagents: boolean;
|
|
42
|
-
runtime: string;
|
|
43
|
-
};
|
|
44
|
-
opencode: {
|
|
45
|
-
structured_output: boolean;
|
|
46
|
-
supports_session_resume: boolean;
|
|
47
|
-
supports_mcp: boolean;
|
|
48
|
-
supports_skills: boolean;
|
|
49
|
-
supports_live_input: boolean;
|
|
50
|
-
supports_native_subagents: boolean;
|
|
51
|
-
streaming: boolean;
|
|
52
|
-
native_runtime_config: any;
|
|
53
|
-
supports_builtin_tools: boolean;
|
|
54
|
-
supports_fast_mode: boolean;
|
|
55
|
-
runtime: string;
|
|
56
|
-
};
|
|
57
|
-
};
|
package/types/ai/registry.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { listRuntimeBridges as listProviders, resolveRuntimeBridge as findProviderForModel, runtimeCapabilities } from "./runtime/registry.js";
|