@arnilo/prism 0.2.8 → 0.3.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/CHANGELOG.md +17 -0
- package/README.md +14 -6
- package/dist/contracts-protocol.d.ts +31 -1
- package/dist/delegated-agent-step.d.ts +20 -0
- package/dist/delegated-agent-step.js +99 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/oauth-device-code.d.ts +5 -0
- package/dist/oauth-device-code.js +38 -14
- package/docs/0.1.0-readiness.md +8 -8
- package/docs/acp.md +4 -3
- package/docs/ag-ui.md +5 -2
- package/docs/agent-events.md +8 -1
- package/docs/antigravity-agent.md +207 -0
- package/docs/caveman.md +3 -2
- package/docs/coding-agent-tools.md +32 -4
- package/docs/computer-use-linux.md +122 -0
- package/docs/context-and-skills.md +2 -2
- package/docs/credential-storage.md +1 -1
- package/docs/credentials-and-redaction.md +2 -2
- package/docs/device-adapters.md +4 -3
- package/docs/extensions.md +1 -0
- package/docs/impeccable.md +102 -0
- package/docs/index.md +14 -4
- package/docs/mcp-tools.md +1 -1
- package/docs/migration.md +26 -2
- package/docs/ponytail.md +2 -2
- package/docs/provider-caching.md +6 -0
- package/docs/provider-packages.md +19 -6
- package/docs/providers/clinepass.md +120 -0
- package/docs/providers/deepseek.md +147 -0
- package/docs/providers/openai.md +1 -1
- package/docs/providers/xai.md +138 -0
- package/docs/release-and-install.md +92 -29
- package/docs/thinking-and-reasoning.md +6 -3
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [0.3.0] - 2026-08-20
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- **Release 0.3.0 (plans 030, 031)** is the final lockstep cut and first independent-versioning line. The graph contains 57 publishable manifests; internal first-party ranges use `^0.3.0`, Decision B permits changed packages to patch/minor independently inside `<0.4.0`, and later publication uses `@arnilo/<package>@<version>` tags.
|
|
5
|
+
- Optional `@arnilo/prism-antigravity-agent` delegates autonomous coding sessions to the official Google Antigravity CLI (`agy`) with per-run loopback HTTP MCP capability exposure, AG-UI timeline projection, secret redaction, and `--conversation` continuation. Host owns the official binary and `agy login` authentication state.
|
|
6
|
+
- Optional `@arnilo/prism-computer-use-linux` wraps a host-owned Linux `computer-use-linux` MCP binary. DeviceAdapter admission is deny-by-default, setup tools are opt-in, mutating calls require approval/ExecutionPolicy, results are bounded and untrusted, input is serialized, and the package is omitted from umbrellas.
|
|
7
|
+
- Coding/ACP closeouts: `read.findText`, visible fuzzy edit outcomes and nearby miss context, ACP editor-buffer filesystem operations, spawnable per-session coding registries, and delete/move result locations.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Release automation keeps explicit `--lockstep --version 0.3.0` for the final cut, then defaults to changed-package validation/publication and package tags. No Changesets or new core runtime dependency.
|
|
11
|
+
- No persisted store migration. Live-service canaries and delegated Cursor adapter remain later demand-gated 0.3.x work.
|
|
12
|
+
|
|
13
|
+
## [0.2.9] - 2026-08-19
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **Release 0.2.9 (plan 029)** is the provider-adoption and behavior-packages cut. **Additive-only.** New packages: `@arnilo/prism-provider-deepseek`, `@arnilo/prism-provider-xai` (API key + SuperGrok RFC 8628 device-code), `@arnilo/prism-provider-clinepass`, `@arnilo/prism-impeccable`. `pollDeviceCodeToken` accepts `bodyEncoding: "form"` and `extraDeviceParams`. Ponytail peer `^4.9.0` (empty `/ponytail` reports status). Caveman registers extra `SKILL.md`. Graph **55** publishable manifests at exact **0.2.9**. Store-compatible with 0.2.8; no migration. **Publication remains the operator handoff** (`docs/release-and-install.md` `0.2.9 publish handoff` — signed `v0.2.9` tag + npm OIDC).
|
|
17
|
+
|
|
1
18
|
## [0.2.8] - 2026-08-18
|
|
2
19
|
|
|
3
20
|
### Changed
|
package/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
bring their tools, providers, credentials, storage, and UI; Prism supplies the
|
|
5
5
|
common contracts, registries, agent/session runtime, replaceable input/prompt
|
|
6
6
|
and compaction strategies, CLI/RPC adapters, and first-party provider/compaction
|
|
7
|
-
packages.
|
|
7
|
+
packages. The current 0.3.0 line contains 56 publishable manifests, including
|
|
8
|
+
optional Linux desktop control and independent package versioning after the final
|
|
9
|
+
lockstep cut. Prism defines contracts, not apps.
|
|
8
10
|
|
|
9
11
|
## Current scope
|
|
10
12
|
|
|
@@ -18,9 +20,10 @@ packages. Prism defines contracts, not apps.
|
|
|
18
20
|
OpenAI/OpenRouter use best-effort explicit cache hints, NeuralWatt uses
|
|
19
21
|
best-effort implicit prefix caching, and other providers have route/model-specific
|
|
20
22
|
or no cache-control support; see [docs/provider-caching.md](docs/provider-caching.md).
|
|
21
|
-
- **First-party packages**:
|
|
23
|
+
- **First-party packages**: seventeen provider adapters, two compaction strategies,
|
|
22
24
|
coding tools/security, JSON Schema validation, MCP, workflows, OpenTelemetry,
|
|
23
|
-
encrypted credentials, SQLite/PostgreSQL persistence,
|
|
25
|
+
encrypted credentials, SQLite/PostgreSQL persistence, Linux desktop control,
|
|
26
|
+
and manifest-only install profiles.
|
|
24
27
|
- **Tools, context, skills**: host-owned tool registry with allow/deny filtering
|
|
25
28
|
and dispatch, context providers, and a skill registry with progressive
|
|
26
29
|
disclosure.
|
|
@@ -56,7 +59,7 @@ npm install @arnilo/prism @arnilo/prism-provider-openai # core + one provider
|
|
|
56
59
|
npm install @arnilo/prism-base # core + compaction + validation
|
|
57
60
|
npm install @arnilo/prism-code @arnilo/prism-provider-openai # coding-agent profile
|
|
58
61
|
npm install @arnilo/prism-sdk @arnilo/prism-provider-openai # application profile
|
|
59
|
-
npm install @arnilo/prism-all # broad umbrella (21 direct /
|
|
62
|
+
npm install @arnilo/prism-all # broad umbrella (21 direct / 47 workspace packages)
|
|
60
63
|
npm install @arnilo/prism-server @arnilo/prism-workflows # optional Web API boundary
|
|
61
64
|
npm install @arnilo/prism-supervisor # optional local delegation + A2A 1.0
|
|
62
65
|
npm install @arnilo/prism-web-tools # optional bounded Brave/Exa/Firecrawl research
|
|
@@ -160,11 +163,16 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
|
|
|
160
163
|
| `@arnilo/prism-provider-ollama` | Ollama Cloud / local provider with dynamic discovery and implicit-only caching |
|
|
161
164
|
| `@arnilo/prism-provider-anthropic` | Anthropic Messages provider |
|
|
162
165
|
| `@arnilo/prism-provider-google` | Google Gemini provider |
|
|
166
|
+
| `@arnilo/prism-provider-deepseek` | DeepSeek Chat Completions provider |
|
|
167
|
+
| `@arnilo/prism-provider-xai` | xAI Grok Completions + SuperGrok OAuth |
|
|
168
|
+
| `@arnilo/prism-provider-clinepass` | ClinePass OpenAI-compatible gateway |
|
|
163
169
|
| `@arnilo/prism-provider-azure` | Azure OpenAI provider |
|
|
164
170
|
| `@arnilo/prism-provider-bedrock` | AWS Bedrock provider |
|
|
165
171
|
| `@arnilo/prism-provider-vertex` | Google Vertex provider |
|
|
166
172
|
| `@arnilo/prism-provider-ai-sdk` | AI SDK interoperability adapter |
|
|
167
173
|
| `@arnilo/prism-browser` | optional host-wired Playwright browser automation (not core; not auto-activated) |
|
|
174
|
+
| `@arnilo/prism-computer-use-linux` | optional Linux desktop-control tools over a host-owned `computer-use-linux` MCP binary |
|
|
175
|
+
| `@arnilo/prism-antigravity-agent` | optional Antigravity CLI delegated agent adapter with per-run Prism MCP capability exposure |
|
|
168
176
|
| `@arnilo/prism-compaction-llm` | provider-backed compaction strategy |
|
|
169
177
|
| `@arnilo/prism-compaction-observational-memory` | source-backed memory + recall tool |
|
|
170
178
|
| `@arnilo/prism-coding-agent` | bounded shell/read/write/edit tools |
|
|
@@ -178,12 +186,12 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
|
|
|
178
186
|
| `@arnilo/prism-credentials-node` | encrypted-file and keychain credentials |
|
|
179
187
|
| `@arnilo/prism-session-store-sqlite` | SQLite persistence/checkpoints/leases/owned run feedback |
|
|
180
188
|
| `@arnilo/prism-session-store-postgres` | PostgreSQL persistence/checkpoints/leases/owned run feedback |
|
|
181
|
-
| `@arnilo/prism-providers` | family:
|
|
189
|
+
| `@arnilo/prism-providers` | family: 14 of 17 first-party provider adapters (omits Azure, Bedrock, Vertex, which `prism-all` adds separately), including AI SDK interoperability |
|
|
182
190
|
| `@arnilo/prism-compaction` | family: both compaction strategies |
|
|
183
191
|
| `@arnilo/prism-base` | profile: core + compaction + JSON Schema validation |
|
|
184
192
|
| `@arnilo/prism-code` | profile: base + coding tools/security + MCP |
|
|
185
193
|
| `@arnilo/prism-sdk` | profile: base + workflows + MCP + credentials + OpenTelemetry |
|
|
186
|
-
| `@arnilo/prism-all` | broad umbrella: 21 first-party packages (
|
|
194
|
+
| `@arnilo/prism-all` | broad umbrella: 21 first-party packages (47 transitive) across a 47-package workspace closure — omits document-reader, OpenAPI tools, NATS, Caveman, Ponytail, Impeccable, computer-use-linux, and antigravity-agent |
|
|
187
195
|
|
|
188
196
|
## Scripts
|
|
189
197
|
|
|
@@ -108,6 +108,36 @@ export interface ToolExecutionMetadata {
|
|
|
108
108
|
readonly durationMs: number;
|
|
109
109
|
readonly status: ToolCallStatus;
|
|
110
110
|
}
|
|
111
|
+
export type DelegatedAgentStepState = "active" | "done" | "error";
|
|
112
|
+
export type DelegatedAgentStepKind = "assistant" | "tool" | "subagent" | "checkpoint" | "unknown";
|
|
113
|
+
/** Token counters only; delegated adapters must never put thought text in this shape. */
|
|
114
|
+
export interface DelegatedAgentStepUsage {
|
|
115
|
+
readonly inputTokens?: number;
|
|
116
|
+
readonly outputTokens?: number;
|
|
117
|
+
readonly thinkingTokens?: number;
|
|
118
|
+
readonly cacheReadTokens?: number;
|
|
119
|
+
readonly cacheWriteTokens?: number;
|
|
120
|
+
readonly totalTokens?: number;
|
|
121
|
+
}
|
|
122
|
+
/** Safe delegated timeline metadata. Raw arguments, results, paths, URIs, and event bodies are not fields. */
|
|
123
|
+
export interface DelegatedAgentStep {
|
|
124
|
+
readonly type: "delegated_agent_step";
|
|
125
|
+
readonly sessionId: string;
|
|
126
|
+
readonly runId: string;
|
|
127
|
+
readonly adapterId: string;
|
|
128
|
+
readonly externalConversationId: string;
|
|
129
|
+
readonly stepIndex: number;
|
|
130
|
+
readonly state: DelegatedAgentStepState;
|
|
131
|
+
readonly kind: DelegatedAgentStepKind;
|
|
132
|
+
readonly durationMs?: number;
|
|
133
|
+
readonly usage?: DelegatedAgentStepUsage;
|
|
134
|
+
readonly toolName?: string;
|
|
135
|
+
readonly subagentType?: string;
|
|
136
|
+
readonly detail?: {
|
|
137
|
+
readonly referenceId?: string;
|
|
138
|
+
readonly label?: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
111
141
|
export type AgentFinishReason = "turn_limit" | "token_limit" | "refusal";
|
|
112
142
|
export type AgentEvent = {
|
|
113
143
|
readonly type: "agent_started";
|
|
@@ -176,7 +206,7 @@ export type AgentEvent = {
|
|
|
176
206
|
readonly sessionId: string;
|
|
177
207
|
readonly runId: string;
|
|
178
208
|
readonly message: Message;
|
|
179
|
-
} | {
|
|
209
|
+
} | DelegatedAgentStep | {
|
|
180
210
|
readonly type: "tool_execution_started";
|
|
181
211
|
readonly sessionId: string;
|
|
182
212
|
readonly runId: string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DelegatedAgentStep } from "./contracts-protocol.js";
|
|
2
|
+
export declare const MAX_DELEGATED_AGENT_EVENT_BYTES: number;
|
|
3
|
+
export declare const MAX_DELEGATED_AGENT_ID_BYTES = 512;
|
|
4
|
+
export declare const MAX_DELEGATED_AGENT_NAME_BYTES = 256;
|
|
5
|
+
export declare const MAX_DELEGATED_AGENT_STEP_INDEX = 1000000;
|
|
6
|
+
export declare const MAX_DELEGATED_AGENT_DURATION_MS: number;
|
|
7
|
+
export declare const MAX_DELEGATED_AGENT_TOKEN_COUNT = 1000000000000;
|
|
8
|
+
export interface DelegatedAgentStepInput extends Omit<DelegatedAgentStep, "type" | "kind" | "state"> {
|
|
9
|
+
readonly kind: string;
|
|
10
|
+
readonly state: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class DelegatedAgentStepError extends Error {
|
|
13
|
+
readonly code = "ERR_PRISM_DELEGATED_AGENT_STEP";
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Builds the only safe core shape for delegated timeline metadata. Unknown step
|
|
18
|
+
* kinds become `unknown`; unbounded or malformed identity/counter fields fail closed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createDelegatedAgentStep(input: DelegatedAgentStepInput): DelegatedAgentStep;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export const MAX_DELEGATED_AGENT_EVENT_BYTES = 64 * 1024;
|
|
2
|
+
export const MAX_DELEGATED_AGENT_ID_BYTES = 512;
|
|
3
|
+
export const MAX_DELEGATED_AGENT_NAME_BYTES = 256;
|
|
4
|
+
export const MAX_DELEGATED_AGENT_STEP_INDEX = 1_000_000;
|
|
5
|
+
export const MAX_DELEGATED_AGENT_DURATION_MS = 24 * 60 * 60 * 1000;
|
|
6
|
+
export const MAX_DELEGATED_AGENT_TOKEN_COUNT = 1_000_000_000_000;
|
|
7
|
+
export class DelegatedAgentStepError extends Error {
|
|
8
|
+
code = "ERR_PRISM_DELEGATED_AGENT_STEP";
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "DelegatedAgentStepError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Builds the only safe core shape for delegated timeline metadata. Unknown step
|
|
16
|
+
* kinds become `unknown`; unbounded or malformed identity/counter fields fail closed.
|
|
17
|
+
*/
|
|
18
|
+
export function createDelegatedAgentStep(input) {
|
|
19
|
+
if (!input || typeof input !== "object")
|
|
20
|
+
throw invalid("event");
|
|
21
|
+
const state = input.state;
|
|
22
|
+
if (state !== "active" && state !== "done" && state !== "error")
|
|
23
|
+
throw invalid("state");
|
|
24
|
+
const kind = normalizeKind(input.kind);
|
|
25
|
+
if (!Number.isSafeInteger(input.stepIndex) || input.stepIndex < 0 || input.stepIndex > MAX_DELEGATED_AGENT_STEP_INDEX) {
|
|
26
|
+
throw invalid("stepIndex");
|
|
27
|
+
}
|
|
28
|
+
const event = {
|
|
29
|
+
type: "delegated_agent_step",
|
|
30
|
+
sessionId: boundedText(input.sessionId, "sessionId", MAX_DELEGATED_AGENT_ID_BYTES),
|
|
31
|
+
runId: boundedText(input.runId, "runId", MAX_DELEGATED_AGENT_ID_BYTES),
|
|
32
|
+
adapterId: boundedText(input.adapterId, "adapterId", MAX_DELEGATED_AGENT_ID_BYTES),
|
|
33
|
+
externalConversationId: boundedText(input.externalConversationId, "externalConversationId", MAX_DELEGATED_AGENT_ID_BYTES),
|
|
34
|
+
stepIndex: input.stepIndex,
|
|
35
|
+
state,
|
|
36
|
+
kind,
|
|
37
|
+
...(input.durationMs === undefined
|
|
38
|
+
? {}
|
|
39
|
+
: { durationMs: boundedNumber(input.durationMs, "durationMs", MAX_DELEGATED_AGENT_DURATION_MS) }),
|
|
40
|
+
...(input.usage === undefined ? {} : { usage: normalizeUsage(input.usage) }),
|
|
41
|
+
...(input.toolName === undefined ? {} : { toolName: boundedText(input.toolName, "toolName", MAX_DELEGATED_AGENT_NAME_BYTES) }),
|
|
42
|
+
...(input.subagentType === undefined
|
|
43
|
+
? {}
|
|
44
|
+
: { subagentType: boundedText(input.subagentType, "subagentType", MAX_DELEGATED_AGENT_NAME_BYTES) }),
|
|
45
|
+
...(input.detail === undefined ? {} : { detail: normalizeDetail(input.detail) }),
|
|
46
|
+
};
|
|
47
|
+
if (utf8Bytes(JSON.stringify(event)) > MAX_DELEGATED_AGENT_EVENT_BYTES)
|
|
48
|
+
throw invalid("event bytes");
|
|
49
|
+
return event;
|
|
50
|
+
}
|
|
51
|
+
function normalizeKind(value) {
|
|
52
|
+
return value === "assistant" || value === "tool" || value === "subagent" || value === "checkpoint" || value === "unknown"
|
|
53
|
+
? value
|
|
54
|
+
: "unknown";
|
|
55
|
+
}
|
|
56
|
+
function normalizeUsage(value) {
|
|
57
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
58
|
+
throw invalid("usage");
|
|
59
|
+
const output = {};
|
|
60
|
+
for (const key of ["inputTokens", "outputTokens", "thinkingTokens", "cacheReadTokens", "cacheWriteTokens", "totalTokens"]) {
|
|
61
|
+
const amount = value[key];
|
|
62
|
+
if (amount === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
output[key] = boundedNumber(amount, key, MAX_DELEGATED_AGENT_TOKEN_COUNT);
|
|
65
|
+
}
|
|
66
|
+
return output;
|
|
67
|
+
}
|
|
68
|
+
function normalizeDetail(value) {
|
|
69
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
70
|
+
throw invalid("detail");
|
|
71
|
+
const referenceId = value.referenceId === undefined ? undefined : boundedOpaque(value.referenceId, "detail.referenceId", MAX_DELEGATED_AGENT_ID_BYTES);
|
|
72
|
+
const label = value.label === undefined ? undefined : boundedText(value.label, "detail.label", MAX_DELEGATED_AGENT_NAME_BYTES);
|
|
73
|
+
return {
|
|
74
|
+
...(referenceId === undefined ? {} : { referenceId }),
|
|
75
|
+
...(label === undefined ? {} : { label }),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function boundedText(value, name, maxBytes) {
|
|
79
|
+
if (typeof value !== "string" || value.length === 0 || /[\0\r\n]/.test(value) || utf8Bytes(value) > maxBytes)
|
|
80
|
+
throw invalid(name);
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function boundedOpaque(value, name, maxBytes) {
|
|
84
|
+
if (typeof value !== "string" || /[\\/:]/.test(value))
|
|
85
|
+
throw invalid(name);
|
|
86
|
+
return boundedText(value, name, maxBytes);
|
|
87
|
+
}
|
|
88
|
+
function boundedNumber(value, name, max) {
|
|
89
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > max)
|
|
90
|
+
throw invalid(name);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
function utf8Bytes(value) {
|
|
94
|
+
return new TextEncoder().encode(value).byteLength;
|
|
95
|
+
}
|
|
96
|
+
function invalid(field) {
|
|
97
|
+
return new DelegatedAgentStepError(`Invalid delegated agent step ${field}`);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=delegated-agent-step.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export type { DeviceAdapter, DeviceAdmitRequest, DeviceChunkResult, DeviceConfor
|
|
|
37
37
|
export { acceptDeviceChunk, assertDeviceAdmit, DEFAULT_DEVICE_MAX_CHUNK_BYTES, DEFAULT_DEVICE_MAX_CONCURRENT_SESSIONS, DevicePolicyError, HARD_DEVICE_MAX_CHUNK_BYTES, HARD_DEVICE_MAX_CONCURRENT_SESSIONS, redactDeviceTelemetry, resolveDevicePolicy, runDevicePolicyConformance, } from "./devices.js";
|
|
38
38
|
export type { EventMultiplexer, EventMultiplexerOptions, EventOverflowInfo, EventOverflowPolicy } from "./event-multiplexer.js";
|
|
39
39
|
export { createEventMultiplexer, EVENT_MULTIPLEXER_SINGLE_CONSUMER_CODE, EventMultiplexerError } from "./event-multiplexer.js";
|
|
40
|
+
export { createDelegatedAgentStep, DelegatedAgentStepError, MAX_DELEGATED_AGENT_DURATION_MS, MAX_DELEGATED_AGENT_EVENT_BYTES, MAX_DELEGATED_AGENT_ID_BYTES, MAX_DELEGATED_AGENT_NAME_BYTES, MAX_DELEGATED_AGENT_STEP_INDEX, MAX_DELEGATED_AGENT_TOKEN_COUNT, } from "./delegated-agent-step.js";
|
|
41
|
+
export type { DelegatedAgentStepInput } from "./delegated-agent-step.js";
|
|
40
42
|
export type { ExecutionAction, ExecutionDecision, ExecutionPolicy, ExecutionRisk } from "./execution-policy.js";
|
|
41
43
|
export { applyExecutionDecision, assertExecutionAllowed, checkExecution, ExecutionDeniedError } from "./execution-policy.js";
|
|
42
44
|
export type { ExtensionErrorPolicy, ExtensionEventBus, ExtensionEventHandler, ExtensionKernel, ExtensionKernelOptions, ExtensionLoadPolicy, LoadedExtension, } from "./extensions.js";
|
|
@@ -111,5 +113,5 @@ export { createToolParameterValidator, createToolRegistry, dispatchToolCall, fil
|
|
|
111
113
|
export type { ResolvedUseCaseModel, ResolveUseCaseModelInput, UseCaseModelBinding, } from "./use-case-model.js";
|
|
112
114
|
export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
|
|
113
115
|
export declare const name = "prism";
|
|
114
|
-
export declare const version = "0.
|
|
116
|
+
export declare const version = "0.3.0";
|
|
115
117
|
export declare const description = "Agent harness for AI providers, agents, sessions, and tools.";
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ export { CONVERSATION_METADATA_KEY, ConversationError, conversationMarkerMetadat
|
|
|
19
19
|
export { createChainedCredentialResolver, createEnvCredentialResolver, createExplicitCredentialResolver, createMemoryCredentialStore, refreshOAuthCredential, resolveCredentialValue, revokeOAuthCredential, } from "./credentials.js";
|
|
20
20
|
export { acceptDeviceChunk, assertDeviceAdmit, DEFAULT_DEVICE_MAX_CHUNK_BYTES, DEFAULT_DEVICE_MAX_CONCURRENT_SESSIONS, DevicePolicyError, HARD_DEVICE_MAX_CHUNK_BYTES, HARD_DEVICE_MAX_CONCURRENT_SESSIONS, redactDeviceTelemetry, resolveDevicePolicy, runDevicePolicyConformance, } from "./devices.js";
|
|
21
21
|
export { createEventMultiplexer, EVENT_MULTIPLEXER_SINGLE_CONSUMER_CODE, EventMultiplexerError } from "./event-multiplexer.js";
|
|
22
|
+
export { createDelegatedAgentStep, DelegatedAgentStepError, MAX_DELEGATED_AGENT_DURATION_MS, MAX_DELEGATED_AGENT_EVENT_BYTES, MAX_DELEGATED_AGENT_ID_BYTES, MAX_DELEGATED_AGENT_NAME_BYTES, MAX_DELEGATED_AGENT_STEP_INDEX, MAX_DELEGATED_AGENT_TOKEN_COUNT, } from "./delegated-agent-step.js";
|
|
22
23
|
export { applyExecutionDecision, assertExecutionAllowed, checkExecution, ExecutionDeniedError } from "./execution-policy.js";
|
|
23
24
|
export { createExtensionEventBus, createExtensionKernel } from "./extensions.js";
|
|
24
25
|
export { createMemoryRunFeedbackStore, prepareRunFeedback, RunFeedbackError, requireRunFeedbackOwnership, runFeedbackPageLimit, } from "./feedback.js";
|
|
@@ -61,6 +62,6 @@ export { DEFAULT_TOOL_RESULT_FOLD_MAX_SUMMARY_BYTES, DEFAULT_TOOL_RESULT_FOLD_MI
|
|
|
61
62
|
export { createToolParameterValidator, createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
|
|
62
63
|
export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
|
|
63
64
|
export const name = "prism";
|
|
64
|
-
export const version = "0.
|
|
65
|
+
export const version = "0.3.0";
|
|
65
66
|
export const description = "Agent harness for AI providers, agents, sessions, and tools.";
|
|
66
67
|
//# sourceMappingURL=index.js.map
|
|
@@ -14,6 +14,7 @@ export interface OAuthDeviceCodePayload {
|
|
|
14
14
|
readonly device_code: string;
|
|
15
15
|
readonly user_code: string;
|
|
16
16
|
readonly verification_uri: string;
|
|
17
|
+
readonly verification_uri_complete?: string;
|
|
17
18
|
readonly expires_in?: number;
|
|
18
19
|
readonly interval?: number;
|
|
19
20
|
}
|
|
@@ -35,6 +36,10 @@ export interface PollDeviceCodeTokenOptions {
|
|
|
35
36
|
readonly scope?: string;
|
|
36
37
|
/** Extra token-request params merged into every poll body (e.g. client_secret, audience). Never logged. */
|
|
37
38
|
readonly extraTokenParams?: Readonly<Record<string, string>>;
|
|
39
|
+
/** Extra device-code params merged into the device-code body only (e.g. referrer). Never logged. */
|
|
40
|
+
readonly extraDeviceParams?: Readonly<Record<string, string>>;
|
|
41
|
+
/** Wire encoding for device-code and token POSTs. Default `json` keeps Codex / M365 callers byte-compatible. */
|
|
42
|
+
readonly bodyEncoding?: "json" | "form";
|
|
38
43
|
readonly callbacks?: Pick<OAuthLoginCallbacks, "onDeviceCode" | "signal">;
|
|
39
44
|
/** Message prefix, e.g. "OpenAI" or the adapter id. */
|
|
40
45
|
readonly errorPrefix: string;
|
|
@@ -45,6 +45,22 @@ const isTokenSuccessPayload = (value) => {
|
|
|
45
45
|
return false;
|
|
46
46
|
return typeof value.access_token === "string";
|
|
47
47
|
};
|
|
48
|
+
const encodeOAuthBody = (encoding, params) => encoding === "form"
|
|
49
|
+
? { contentType: "application/x-www-form-urlencoded", body: new URLSearchParams(params).toString() }
|
|
50
|
+
: { contentType: "application/json", body: JSON.stringify(params) };
|
|
51
|
+
const requireHttpsVerificationUri = (value, label, errorPrefix, secrets) => {
|
|
52
|
+
let parsed;
|
|
53
|
+
try {
|
|
54
|
+
parsed = new URL(value);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw redactOAuthError(new Error(`${errorPrefix} ${label} must be https`), secrets);
|
|
58
|
+
}
|
|
59
|
+
if (parsed.protocol !== "https:") {
|
|
60
|
+
throw redactOAuthError(new Error(`${errorPrefix} ${label} must be https`), secrets);
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
};
|
|
48
64
|
/**
|
|
49
65
|
* Request a device code, surface it through `onDeviceCode`, then poll the token
|
|
50
66
|
* endpoint until success, expiry, a terminal OAuth error, or abort. All response
|
|
@@ -53,16 +69,19 @@ const isTokenSuccessPayload = (value) => {
|
|
|
53
69
|
* bounded text parsed as JSON with a redacted-text fallback.
|
|
54
70
|
*/
|
|
55
71
|
export async function pollDeviceCodeToken(options) {
|
|
56
|
-
const { fetchImpl, deviceCodeUrl, tokenUrl, clientId, scope, extraTokenParams, callbacks, errorPrefix, parseTokenCredentials } = options;
|
|
72
|
+
const { fetchImpl, deviceCodeUrl, tokenUrl, clientId, scope, extraTokenParams, extraDeviceParams, callbacks, errorPrefix, parseTokenCredentials, } = options;
|
|
73
|
+
const bodyEncoding = options.bodyEncoding === "form" ? "form" : "json";
|
|
57
74
|
const now = options.now ?? Date.now;
|
|
58
75
|
const sleep = options.sleep ?? abortableSleep;
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
const deviceBody = encodeOAuthBody(bodyEncoding, {
|
|
77
|
+
client_id: clientId,
|
|
78
|
+
...(scope ? { scope } : {}),
|
|
79
|
+
...extraDeviceParams,
|
|
80
|
+
});
|
|
62
81
|
const response = await fetchImpl(deviceCodeUrl, {
|
|
63
82
|
method: "POST",
|
|
64
|
-
headers: { "content-type":
|
|
65
|
-
body:
|
|
83
|
+
headers: { "content-type": deviceBody.contentType },
|
|
84
|
+
body: deviceBody.body,
|
|
66
85
|
signal: callbacks?.signal,
|
|
67
86
|
});
|
|
68
87
|
if (!response.ok) {
|
|
@@ -71,10 +90,14 @@ export async function pollDeviceCodeToken(options) {
|
|
|
71
90
|
}
|
|
72
91
|
const json = await readBoundedResponseJson(response, { shape: isDeviceCodePayload });
|
|
73
92
|
const secrets = [json.device_code, json.user_code];
|
|
93
|
+
requireHttpsVerificationUri(json.verification_uri, "verification_uri", errorPrefix, secrets);
|
|
94
|
+
const verificationUri = typeof json.verification_uri_complete === "string" && json.verification_uri_complete.length > 0
|
|
95
|
+
? requireHttpsVerificationUri(json.verification_uri_complete, "verification_uri_complete", errorPrefix, secrets)
|
|
96
|
+
: json.verification_uri;
|
|
74
97
|
const expiresAtMs = now() + (json.expires_in ?? 0) * 1_000;
|
|
75
98
|
await callbacks?.onDeviceCode?.({
|
|
76
99
|
userCode: json.user_code,
|
|
77
|
-
verificationUri
|
|
100
|
+
verificationUri,
|
|
78
101
|
expiresAt: json.expires_in ? new Date(expiresAtMs).toISOString() : undefined,
|
|
79
102
|
});
|
|
80
103
|
let intervalMs = Math.max(1, (json.interval ?? DEFAULT_DEVICE_POLL_INTERVAL_MS / 1_000) * 1_000);
|
|
@@ -82,15 +105,16 @@ export async function pollDeviceCodeToken(options) {
|
|
|
82
105
|
throwIfAborted(callbacks?.signal);
|
|
83
106
|
await sleep(intervalMs, callbacks?.signal);
|
|
84
107
|
throwIfAborted(callbacks?.signal);
|
|
108
|
+
const tokenBody = encodeOAuthBody(bodyEncoding, {
|
|
109
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
110
|
+
client_id: clientId,
|
|
111
|
+
device_code: json.device_code,
|
|
112
|
+
...extraTokenParams,
|
|
113
|
+
});
|
|
85
114
|
const tokenResponse = await fetchImpl(tokenUrl, {
|
|
86
115
|
method: "POST",
|
|
87
|
-
headers: { "content-type":
|
|
88
|
-
body:
|
|
89
|
-
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
90
|
-
client_id: clientId,
|
|
91
|
-
device_code: json.device_code,
|
|
92
|
-
...extraTokenParams,
|
|
93
|
-
}),
|
|
116
|
+
headers: { "content-type": tokenBody.contentType },
|
|
117
|
+
body: tokenBody.body,
|
|
94
118
|
signal: callbacks?.signal,
|
|
95
119
|
});
|
|
96
120
|
if (tokenResponse.ok) {
|
package/docs/0.1.0-readiness.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 0.1.0 / 1.0 Readiness Gates
|
|
2
2
|
|
|
3
|
-
Status: **0.
|
|
3
|
+
Status: **0.3.0** is the current release line (the final 0.3.x lockstep cut: Linux desktop wrapper, coding/ACP closeouts, and independent package versions with Decision B `^0.3.0` ranges); **0.1.7** was the terminal 0.1.x baseline; **1.0** readiness remains operator-gated, not automatic.
|
|
4
4
|
|
|
5
5
|
This page distills runnable readiness gates into one command-per-gate table.
|
|
6
6
|
The **Last evidence** column records the 0.1.0-tree snapshot (plan 012 Tasks
|
|
@@ -20,16 +20,16 @@ Historical release lines (0.0.16 floor → 0.0.27 Phase 10 ACP interop → 0.1.0
|
|
|
20
20
|
keep their per-phase evidence in the pages above; this page records the 0.2.6
|
|
21
21
|
snapshot (plan 026) with the 0.1.x tables below as the historical record.
|
|
22
22
|
|
|
23
|
-
## Current line (0.
|
|
23
|
+
## Current line (0.3.0)
|
|
24
24
|
|
|
25
25
|
| Item | Status |
|
|
26
26
|
|---|---|
|
|
27
|
-
|
|
|
28
|
-
| Current-line cut | The 0.
|
|
29
|
-
| Upgrade path | `docs/migration.md` `0.2.
|
|
30
|
-
| Compat promise | Additive-only vs the frozen 0.
|
|
31
|
-
| Security policy | `npm audit --audit-level=moderate` 0 at 0.
|
|
32
|
-
| Docs freeze | tripwires green including the
|
|
27
|
+
| Release graph | **56** publishable manifests at exact **0.3.0** (root + 55 workspace packages: 17 provider adapters + 10 `prism-*` family/profile + 28 capability; generated by `node scripts/package-truth.mjs` → `scripts/package-truth.json`; npm publication remains the operator handoff) |
|
|
28
|
+
| Current-line cut | The 0.3.x line starts with the final lockstep cut: optional host-owned Linux desktop control, coding/ACP tool closeouts, and independent package publication after the cut; live canaries and delegated agents remain later demand-gated work |
|
|
29
|
+
| Upgrade path | `docs/migration.md` `0.2.9 → 0.3.0` (additive; no store migration; rollback = restore 0.2.9 manifests/tag); internal first-party ranges become `^0.3.0` |
|
|
30
|
+
| Compat promise | Additive-only vs the frozen 0.2.9 baseline; package peers use Decision B's `^0.3.0` caret window and `scripts/compat-baseline` remains the reviewed declaration gate |
|
|
31
|
+
| Security policy | `npm audit --audit-level=moderate` 0 target at 0.3.0; desktop admission remains deny-by-default, mutators require approval + `ExecutionPolicy`, and package tags publish only changed packages |
|
|
32
|
+
| Docs freeze | tripwires green including the 56-package truth graph, Decision B range policy, the plan 030 freeze/release tests, coding/ACP tool regressions, and the host-owned desktop wrapper's fail-closed package/docs gates |
|
|
33
33
|
| 0.1.x line | **0.1.7** (plan 019) is the terminal 0.1.x baseline; the 0.1.1 table below keeps the plan 013 snapshot; the 0.1.0 table keeps the plan 012 snapshot; the **0.0.16** values remain the historical network-free floor |
|
|
34
34
|
|
|
35
35
|
## Previous line (0.1.1)
|
package/docs/acp.md
CHANGED
|
@@ -46,7 +46,7 @@ In-stream `SessionUpdate`s:
|
|
|
46
46
|
| Assistant text | `agent_message_chunk` |
|
|
47
47
|
| Assistant thinking | `agent_thought_chunk` (same `messageId` scheme as text; through the shared redactor and byte caps) |
|
|
48
48
|
| Tool lifecycle | `tool_call` / `tool_call_update` (title/status/content) — `tool_call.kind` comes from the session's tool registry `kind` metadata when present (B4), else the name heuristic |
|
|
49
|
-
| Tool result, projected | `tool_call_update` with `locations` (≤ `acpLocationsPerUpdate`) and/or a `diff` block (≤ `acpDiffBytes`) — only from `AgUiProjection.toolLocations`/`toolDiff` allow-lists, at `finish()`. `toolResult` may return a string (text content) or `{ type: "image", data, mimeType }` (F8) — the mapper wraps the image as `{ type: "content", content: { type: "image", data, mimeType } }` and drops payloads over `acpImageBytes` (never truncated). Opt-in turnkey: `createCodingToolProjection()` (F7) recognizes first-party `edit` (path + unified patch as `newText`, `firstChangedLine` location) and `
|
|
49
|
+
| Tool result, projected | `tool_call_update` with `locations` (≤ `acpLocationsPerUpdate`) and/or a `diff` block (≤ `acpDiffBytes`) — only from `AgUiProjection.toolLocations`/`toolDiff` allow-lists, at `finish()`. `toolResult` may return a string (text content) or `{ type: "image", data, mimeType }` (F8) — the mapper wraps the image as `{ type: "content", content: { type: "image", data, mimeType } }` and drops payloads over `acpImageBytes` (never truncated). Opt-in turnkey: `createCodingToolProjection()` (F7) recognizes first-party `edit` (path + unified patch as `newText`, `firstChangedLine` location), `write` and `delete` (metadata path locations), and `move` (destination `metadata.to` location) results; moves never emit diffs, and default remains deny-by-default. |
|
|
50
50
|
| Provider usage | `usage_update` (only when the `capabilities.usage.contextWindow` seam reports a valid window — absent/undefined/throw ⇒ the update is omitted, never `size = used`) |
|
|
51
51
|
| Run-level failure | No transcript chunk — the `session/prompt` request rejects with `ERR_PRISM_ACP_RUN` (redacted, byte-capped message). Retryable provider-turn failures stay silent and may recover; only a terminal `error` event fails the request. |
|
|
52
52
|
| Run stop reason | `session/prompt` returns the SDK `StopReason` (F4): `cancelled` when the run was aborted, `max_turn_requests` for the tool-round ceiling (`finishReason: "turn_limit"`), `max_tokens` for `"token_limit"`, `refusal` for `"refusal"`, else `end_turn`. The generic `finishReason` field is set on `agent_finished` by loop strategies (single-shot records `turn_limit` at the `maxToolRounds` ceiling); `token_limit`/`refusal` have no core producer yet — the mapping is ready. |
|
|
@@ -112,7 +112,8 @@ const agent = createPrismAcpAgent({
|
|
|
112
112
|
|
|
113
113
|
- **Seam = capability.** Wiring `sessions.load` advertises `loadSession`; removing it withdraws the method. There is no separate capability flag to keep in sync — the freeze manifest's advertise-when matrix is enforced by construction and asserted by `scripts/phase10-conformance.test.mjs`.
|
|
114
114
|
- **Transcript replay (F2).** When `sessions.transcript` is wired, `session/load` and `session/resume` replay `user_message_chunk`/`agent_message_chunk` text chunks (from `SessionEntry`s with `kind: "message"` and a user/assistant role, text blocks only) before returning `sessionState`. Each chunk passes the shared redactor and is truncated at `maxTextBytes`; replay stops at `maxReplayEvents` chunks and counts against the stream event/byte caps (an oversized transcript fails the load/resume request closed). Absent seam = no replay, behavior unchanged.
|
|
115
|
-
- **Client fs/terminal are adapters, not a second implementation.** `AcpClientFilesystem` / `AcpClientTerminals` wrap the client's `fs/*` and `terminal/*` methods behind the Phase 9 `ProcessSession`-flavored interfaces; the agent pre-generates the session id so terminal requests can carry it. Host repo operations remain default when the client fs is absent.
|
|
115
|
+
- **Client fs/terminal are adapters, not a second implementation.** `AcpClientFilesystem` / `AcpClientTerminals` wrap the client's `fs/*` and `terminal/*` methods behind the Phase 9 `ProcessSession`-flavored interfaces; the agent pre-generates the session id so terminal requests can carry it. `createAcpFilesystemOperations` from `@arnilo/prism-coding-agent` maps that filesystem seam onto the coding tools' `read`/`write`/`edit` operations. This editor-buffer mode is intentionally hybrid: `repo_list`, `repo_search`, `glob`, `delete`, and `move` remain disk-backed unless the host supplies separate operations; binary/image/document handling never falls back to local disk. Host repo operations remain default when the client fs is absent.
|
|
116
|
+
- **Spawnable ACP coding registry (Task 6).** `@arnilo/prism-acp-agent` wires `createAcpClientFilesystem` and creates a separate coding tool registry per ACP session when the client advertises `fs/read_text_file` or `fs/write_text_file`. That session's `read`/`write`/`edit` operations use editor buffers; without fs advertisement, the existing disk registry is used. `shell`, repository search/list/glob, `delete`, and `move` remain disk-backed in this hybrid mode. Durable approvals resolve the same per-session agent, so one session cannot resume through another session's buffer adapter.
|
|
116
117
|
- **Modes and config options are a pure host overlay.** The agent stores only a thin per-session registry; `apply`/`onChange` hooks narrow the host's own behavior. Mode switches can narrow or host-authorized widen — never a parallel policy evaluator, never a client-enabled tool.
|
|
117
118
|
- **Lifecycle wiring.** Pass your `createCodingLifecycleEmitter()` as `coding.lifecycle`; `file_changed` etc. then flow to streaming sessions. `configuration_changed` broadcasts `config_option_update` (agent-message fallback if the SDK rejects the kind).
|
|
118
119
|
- **Stream budgets.** Every lifecycle update counts against the same per-run stream event/byte budget as prompt updates; overflowing closes the update, never the run.
|
|
@@ -151,7 +152,7 @@ const agent = createPrismAcpAgent({
|
|
|
151
152
|
- **Deny-closed by default.** Unknown mode ids, unadvertised methods, unprojected lifecycle events, oversize diffs/locations/media, thrown projection hooks, and failed elicitation all fail closed. Raw tool arguments/results are never sent unless a projection allow-list says otherwise.
|
|
152
153
|
- **Slash commands (F9).** `commands.list` is a host-owned slash-command list (not derived from the tool registry). The agent emits `available_commands_update` on session start (`session/new`, `session/load`, `session/resume`). Mid-session refresh is not in this release — re-list by starting a session. Names, descriptions, and input hints pass the shared redactor; the list is sliced at `acpCommandsPerUpdate`. Absent seam or a thrown list ⇒ no update.
|
|
153
154
|
- **Projected images (F8).** `AgUiProjection.toolResult` may return `{ type: "image", data, mimeType }` (return-type widening — existing string returns stay valid). The mapper emits `{ type: "content", content: { type: "image", data, mimeType } }` (SDK v1 `ToolCallContent` has no top-level image variant). `data` is the host-supplied base64; it is not redacted and not truncated — payloads over `acpImageBytes` are dropped. Default (no hook / non-image return) emits no image.
|
|
154
|
-
- **Coding-tool projection (F7).** `createCodingToolProjection({ maxDiffBytes? })` is an opt-in `AgUiProjection` for first-party `@arnilo/prism-coding-agent`
|
|
155
|
+
- **Coding-tool projection (F7).** `createCodingToolProjection({ maxDiffBytes? })` is an opt-in `AgUiProjection` for first-party `@arnilo/prism-coding-agent` results: `edit` → `toolDiff` (`path` + unified `patch` as `newText`) and `toolLocations` (`path` + `firstChangedLine`); `write` and `delete` → `toolLocations` (`path` only); `move` → destination `toolLocations` (`metadata.to`, with `from` fallback). No delete/move diff is fabricated. Pass as `projection: createCodingToolProjection()` on the agent/mapper. Mapper still redacts and enforces `acpDiffBytes` / `acpLocationsPerUpdate`; optional `maxDiffBytes` pre-truncates the patch so a slightly-oversize edit is shortened instead of dropped. Without the factory, behavior is unchanged (deny-by-default).
|
|
155
156
|
- **No secrets.** Updates carry no raw file bodies, terminal output is capped by the Phase 9 chunk budget, and the shared redactor is applied before anything leaves the host. `permission_denied` never includes raw args.
|
|
156
157
|
- **Performance.** The adapter is O(1) per update with no unbounded buffering; p95 targets (fs round trip 250 ms, mode switch 250 ms, terminal chunk ack 1000 ms, prompt first update 2000 ms, prompt end 30 s) are recorded by `scripts/benchmark-0.0.27.mjs` and gated in `scripts/budgets.json` `phase10`.
|
|
157
158
|
|
package/docs/ag-ui.md
CHANGED
|
@@ -44,7 +44,9 @@ The handler accepts only `POST` JSON validated with official AG-UI `RunAgentInpu
|
|
|
44
44
|
|
|
45
45
|
## Outputs / response / events
|
|
46
46
|
|
|
47
|
-
The handler returns `text/event-stream`, one `data: <AG-UI event>\n\n` frame per output. Mapper lifecycle is ordered: `RUN_*`, `STEP_*`, `TEXT_MESSAGE_*`, and `TOOL_CALL_*` are deterministic Prism mappings. Host projectors may additionally prove and emit `STATE_SNAPSHOT`/`STATE_DELTA`, `MESSAGES_SNAPSHOT`, `ACTIVITY_*`, current `REASONING_*`, `RAW`, and named `CUSTOM` values.
|
|
47
|
+
The handler returns `text/event-stream`, one `data: <AG-UI event>\n\n` frame per output. Mapper lifecycle is ordered: `RUN_*`, `STEP_*`, `TEXT_MESSAGE_*`, and `TOOL_CALL_*` are deterministic Prism mappings. Host projectors may additionally prove and emit `STATE_SNAPSHOT`/`STATE_DELTA`, `MESSAGES_SNAPSHOT`, `ACTIVITY_*`, current `REASONING_*`, `RAW`, and named `CUSTOM` values.
|
|
48
|
+
|
|
49
|
+
`delegated_agent_step` maps by default to bounded `ACTIVITY_SNAPSHOT` metadata with activity type `prism.delegated_agent_step`; `includeCustomEvents: true` also emits `CUSTOM prism.delegated_agent_step`. The safe payload contains adapter/conversation identifiers, step index/state/kind, duration, token counts, tool/subagent names, and opaque detail references only. Normal assistant text remains `TEXT_MESSAGE_*`; delegated events never duplicate transcript text. Raw event bodies, tool arguments/results, paths, URIs, logs, and hidden thought text remain absent unless a host explicitly supplies a projection. All values revalidate against official `EventSchemas`; deprecated `THINKING_*` and convenience chunk events are not produced. Active message/tool/reasoning/step sequences close before error, interruption, or finish.
|
|
48
50
|
|
|
49
51
|
A Prism durable `agent_suspended` returns `RUN_FINISHED` with core interrupt id `${runId}:${version}` and a strict `{ decision: "approve" | "deny" }` schema. `projection.interrupt` may attach bounded expiry/metadata or additional host policy interrupts but must retain that core id. Without `interrupts.resume`, one exact entry is required; `cancelled` means deny. An aggregate policy may validate bounded multiple entries, then returns one current-version core decision. Payloads containing `editedArgs`/`args` always deny: Prism does not mutate persisted tool calls. The adapter checks host authorization, selected run, suspended status, and checkpoint version, then calls `AgentRunLifecycle.resumeStream()` once. Claimed/dispatched tools are never replayed.
|
|
50
52
|
|
|
@@ -122,7 +124,7 @@ See runnable network-free [`examples/ag-ui-server.ts`](../examples/ag-ui-server.
|
|
|
122
124
|
|
|
123
125
|
All identity, authorization, session/thread mapping, durable checkpoint lookup, persistence selection, replay cursor persistence, transport adaptation, MCP bridge/card configuration, app sandbox DOM, remote A2A task correlation, and optional projection are host-owned. The adapter owns no listener, database, background reconnect loop, credential resolver, or UI state.
|
|
124
126
|
|
|
125
|
-
`AgUiProjection` is an allow-list. Without a callback, raw tool arguments/results/progress, arbitrary state/patches/transcripts/activity/reasoning/raw events, paths, ACP locations/diffs/terminals/raw I/O, and frontend-supplied tools remain absent. Reasoning signatures do not become AG-UI encrypted values automatically: a host must explicitly provide an already client-encrypted opaque value. `input.project` is also an allow-list: do not merge client state/forwarded props into ownership, identity, tools, permissions, provider options, or media fetch policy.
|
|
127
|
+
`AgUiProjection` is an allow-list. Without a callback, raw tool arguments/results/progress, arbitrary state/patches/transcripts/activity/reasoning/raw events, delegated raw event bodies, paths, ACP locations/diffs/terminals/raw I/O, and frontend-supplied tools remain absent. Reasoning signatures do not become AG-UI encrypted values automatically: a host must explicitly provide an already client-encrypted opaque value. `input.project` is also an allow-list: do not merge client state/forwarded props into ownership, identity, tools, permissions, provider options, or media fetch policy.
|
|
126
128
|
|
|
127
129
|
### Reasoning encrypted-value helper (FR-3)
|
|
128
130
|
|
|
@@ -222,4 +224,5 @@ Defaults / hard caps: request 64 KiB / 1 MiB; input 128 / 1024 messages, 32 / 25
|
|
|
222
224
|
- [MCP bridge/server](mcp-tools.md): `mcpApps` negotiation, bounded resources, and remote tool trust.
|
|
223
225
|
- [A2A interoperability](a2a.md): verified rich task client and remote task lifecycle.
|
|
224
226
|
- [Host security guide](host-security.md): authorization, ownership, redaction, and credential boundaries.
|
|
227
|
+
- [Antigravity delegated agent](antigravity-agent.md): delegated Antigravity CLI execution with timeline step projection.
|
|
225
228
|
- [Work artifacts and review](work-artifacts-and-review.md): durable artifact service that produces the co-work approval/progress/download-link events projected here.
|
package/docs/agent-events.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`AgentEvent` is the single observable stream every `AgentSession` run emits. Subscribers receive normalized, redacted, in-order events covering agent lifecycle, assistant message streaming, tool execution, queue updates, subscriber overflow, compaction, retry, artifact validation/refinement, and terminal errors. The stream is in-memory, live-only, and bounded per subscriber by `SubscribeOptions`; there is no durable queue, no background work, and no extra dependency.
|
|
5
|
+
`AgentEvent` is the single observable stream every `AgentSession` run emits. Subscribers receive normalized, redacted, in-order events covering agent lifecycle, assistant message streaming, delegated-agent activity, tool execution, queue updates, subscriber overflow, compaction, retry, artifact validation/refinement, and terminal errors. The stream is in-memory, live-only, and bounded per subscriber by `SubscribeOptions`; there is no durable queue, no background work, and no extra dependency.
|
|
6
6
|
|
|
7
7
|
Events are emitted by the runtime and by loops through `LoopContext.emit`, both of which route through `redactAgentEvent(event, activeRedactor)` so every payload is secret-redacted before subscribers observe it.
|
|
8
8
|
|
|
@@ -56,6 +56,7 @@ const subscription = session.subscribe({ maxQueuedEvents: 256, overflow: "close"
|
|
|
56
56
|
for await (const event of subscription) {
|
|
57
57
|
switch (event.type) {
|
|
58
58
|
case "message_delta": // append event.content
|
|
59
|
+
case "delegated_agent_step": // render bounded external activity
|
|
59
60
|
case "tool_execution_started": // …
|
|
60
61
|
case "artifact_failed": // budget exhausted
|
|
61
62
|
break;
|
|
@@ -71,6 +72,7 @@ The `AgentEvent` union (grouped by concern):
|
|
|
71
72
|
| Turns | `turn_started`, `turn_finished` |
|
|
72
73
|
| Provider turns | `provider_turn_started`, `provider_turn_finished` |
|
|
73
74
|
| Assistant messages | `message_started`, `message_delta`, `message_finished` |
|
|
75
|
+
| Delegated agents | `delegated_agent_step` |
|
|
74
76
|
| Tool execution | `tool_execution_started`, `tool_execution_progress`, `tool_execution_finished`, `tool_execution_error`, `tool_execution_blocked` |
|
|
75
77
|
| Guardrails | `guardrail_decision` |
|
|
76
78
|
| Queue/subscribers | `queue_updated`, `event_subscriber_overflow`, `steer_rejected` |
|
|
@@ -95,6 +97,11 @@ Agent / turn / message events:
|
|
|
95
97
|
| `turn_started` / `turn_finished` | `sessionId`, `runId`, `turn: number` |
|
|
96
98
|
| `message_started` / `message_finished` | `sessionId`, `runId`, `message: Message` |
|
|
97
99
|
| `message_delta` | `sessionId`, `runId`, `content: ContentBlock` (`tool_call_delta` fragments may appear here for live UI streaming; stored messages use final `tool_call` blocks) |
|
|
100
|
+
| `delegated_agent_step` | `sessionId`, `runId`, `adapterId`, `externalConversationId` (≤512 UTF-8 bytes), `stepIndex`, `state`, `kind`, optional `durationMs`, token-only `usage`, `toolName`, `subagentType`, and opaque `detail` references |
|
|
101
|
+
|
|
102
|
+
`delegated_agent_step` is a safe timeline event for an adapter-owned loop. `kind` is one of `assistant`, `tool`, `subagent`, `checkpoint`, or `unknown`; unknown external step kinds normalize to `unknown`. It never carries raw arguments, results, paths, URIs, logs, event bodies, or hidden thought text. `thinkingTokens` is a count only. The constructor and existing event-source default cap keep serialized events at 64 KiB.
|
|
103
|
+
|
|
104
|
+
Adapters should call `createDelegatedAgentStep({ sessionId, runId, adapterId, externalConversationId, stepIndex, state, kind, usage })` rather than forwarding external JSON. The constructor allow-lists fields and fails closed on malformed or oversized identifiers/counters.
|
|
98
105
|
|
|
99
106
|
`message_delta.content.type === "tool_call_delta"` carries `{ index, id?, name?, argumentsText? }`. Treat it as a streaming fragment. The runtime reconstructs and persists a final `tool_call` before executing tools. Deltas missing `id`/`name` at stream end fail the provider turn with `ErrorInfo.code: "incomplete_delta"` (typed `ProviderTransportError`); they never throw a bare `Error`. Malformed JSON with id+name present recovers as a blocked tool result (`invalid_json_arguments`) instead.
|
|
100
107
|
|