paseo-agy-acp 2.2.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 +296 -0
- package/LICENSE +201 -0
- package/README.md +571 -0
- package/README.zh-CN.md +540 -0
- package/assets/official-kernel-compat/rc01/paseo_model_compat.py +172 -0
- package/dist/ACP Connector/acp/session/paseo-context.d.ts +6 -0
- package/dist/ACP Connector/acp/session/paseo-context.js +83 -0
- package/dist/ACP Connector/acp/session/paseo-context.js.map +1 -0
- package/dist/ACP Connector/acp/session/turn-scheduler.d.ts +90 -0
- package/dist/ACP Connector/acp/session/turn-scheduler.js +247 -0
- package/dist/ACP Connector/acp/session/turn-scheduler.js.map +1 -0
- package/dist/ACP Connector/admission/dispatch-boundary.d.ts +19 -0
- package/dist/ACP Connector/admission/dispatch-boundary.js +16 -0
- package/dist/ACP Connector/admission/dispatch-boundary.js.map +1 -0
- package/dist/ACP Connector/admission/errors.d.ts +18 -0
- package/dist/ACP Connector/admission/errors.js +46 -0
- package/dist/ACP Connector/admission/errors.js.map +1 -0
- package/dist/ACP Connector/admission/owner-instance.d.ts +31 -0
- package/dist/ACP Connector/admission/owner-instance.js +105 -0
- package/dist/ACP Connector/admission/owner-instance.js.map +1 -0
- package/dist/ACP Connector/admission/runtime.d.ts +20 -0
- package/dist/ACP Connector/admission/runtime.js +157 -0
- package/dist/ACP Connector/admission/runtime.js.map +1 -0
- package/dist/ACP Connector/admission/startup-recovery.d.ts +22 -0
- package/dist/ACP Connector/admission/startup-recovery.js +129 -0
- package/dist/ACP Connector/admission/startup-recovery.js.map +1 -0
- package/dist/ACP Connector/admission/turn-coordinator.d.ts +57 -0
- package/dist/ACP Connector/admission/turn-coordinator.js +369 -0
- package/dist/ACP Connector/admission/turn-coordinator.js.map +1 -0
- package/dist/ACP Connector/agent.d.ts +4 -0
- package/dist/ACP Connector/agent.js +6 -0
- package/dist/ACP Connector/agent.js.map +1 -0
- package/dist/ACP Connector/main.d.ts +2 -0
- package/dist/ACP Connector/main.js +31 -0
- package/dist/ACP Connector/main.js.map +1 -0
- package/dist/ACP Connector/official-kernel/admission-fence.d.ts +10 -0
- package/dist/ACP Connector/official-kernel/admission-fence.js +52 -0
- package/dist/ACP Connector/official-kernel/admission-fence.js.map +1 -0
- package/dist/ACP Connector/official-kernel/context.d.ts +3 -0
- package/dist/ACP Connector/official-kernel/context.js +52 -0
- package/dist/ACP Connector/official-kernel/context.js.map +1 -0
- package/dist/ACP Connector/official-kernel/errors.d.ts +5 -0
- package/dist/ACP Connector/official-kernel/errors.js +39 -0
- package/dist/ACP Connector/official-kernel/errors.js.map +1 -0
- package/dist/ACP Connector/official-kernel/identity.d.ts +3 -0
- package/dist/ACP Connector/official-kernel/identity.js +17 -0
- package/dist/ACP Connector/official-kernel/identity.js.map +1 -0
- package/dist/ACP Connector/official-kernel/json-rpc.d.ts +34 -0
- package/dist/ACP Connector/official-kernel/json-rpc.js +26 -0
- package/dist/ACP Connector/official-kernel/json-rpc.js.map +1 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-lifecycle.d.ts +115 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-lifecycle.js +1904 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-lifecycle.js.map +1 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-pins.d.ts +14 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-pins.js +29 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-pins.js.map +1 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-rc01-recipe.d.ts +2 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-rc01-recipe.js +32 -0
- package/dist/ACP Connector/official-kernel/kernel-compat-rc01-recipe.js.map +1 -0
- package/dist/ACP Connector/official-kernel/kernel.d.ts +3 -0
- package/dist/ACP Connector/official-kernel/kernel.js +12 -0
- package/dist/ACP Connector/official-kernel/kernel.js.map +1 -0
- package/dist/ACP Connector/official-kernel/login.d.ts +1 -0
- package/dist/ACP Connector/official-kernel/login.js +73 -0
- package/dist/ACP Connector/official-kernel/login.js.map +1 -0
- package/dist/ACP Connector/official-kernel/mcp-rewrite.d.ts +1 -0
- package/dist/ACP Connector/official-kernel/mcp-rewrite.js +39 -0
- package/dist/ACP Connector/official-kernel/mcp-rewrite.js.map +1 -0
- package/dist/ACP Connector/official-kernel/mode-map.d.ts +5 -0
- package/dist/ACP Connector/official-kernel/mode-map.js +35 -0
- package/dist/ACP Connector/official-kernel/mode-map.js.map +1 -0
- package/dist/ACP Connector/official-kernel/ndjson.d.ts +3 -0
- package/dist/ACP Connector/official-kernel/ndjson.js +29 -0
- package/dist/ACP Connector/official-kernel/ndjson.js.map +1 -0
- package/dist/ACP Connector/official-kernel/proxy.d.ts +14 -0
- package/dist/ACP Connector/official-kernel/proxy.js +197 -0
- package/dist/ACP Connector/official-kernel/proxy.js.map +1 -0
- package/dist/ACP Connector/official-kernel/run.d.ts +8 -0
- package/dist/ACP Connector/official-kernel/run.js +22 -0
- package/dist/ACP Connector/official-kernel/run.js.map +1 -0
- package/dist/ACP Connector/official-kernel/spawn.d.ts +5 -0
- package/dist/ACP Connector/official-kernel/spawn.js +33 -0
- package/dist/ACP Connector/official-kernel/spawn.js.map +1 -0
- package/dist/Admission Controller/controller.d.ts +338 -0
- package/dist/Admission Controller/controller.js +2089 -0
- package/dist/Admission Controller/controller.js.map +1 -0
- package/dist/Admission Controller/key-derivation.d.ts +24 -0
- package/dist/Admission Controller/key-derivation.js +141 -0
- package/dist/Admission Controller/key-derivation.js.map +1 -0
- package/dist/Admission Controller/key-store.d.ts +8 -0
- package/dist/Admission Controller/key-store.js +280 -0
- package/dist/Admission Controller/key-store.js.map +1 -0
- package/dist/Admission Controller/policy-limits.d.ts +6 -0
- package/dist/Admission Controller/policy-limits.js +11 -0
- package/dist/Admission Controller/policy-limits.js.map +1 -0
- package/dist/Admission Controller/process-evidence.d.ts +111 -0
- package/dist/Admission Controller/process-evidence.js +549 -0
- package/dist/Admission Controller/process-evidence.js.map +1 -0
- package/dist/Admission Controller/runtime-config.d.ts +23 -0
- package/dist/Admission Controller/runtime-config.js +86 -0
- package/dist/Admission Controller/runtime-config.js.map +1 -0
- package/dist/Admission Controller/schema.d.ts +12 -0
- package/dist/Admission Controller/schema.js +422 -0
- package/dist/Admission Controller/schema.js.map +1 -0
- package/package.json +72 -0
- package/scripts/prepare-admission-state-dir.mjs +62 -0
- package/scripts/prepare-official-kernel-compat.mjs +387 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""Local-only request compatibility profile for the RC01 official kernel."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections import deque
|
|
6
|
+
from typing import Any, Deque, Dict, Iterator, Optional, Set, Tuple
|
|
7
|
+
|
|
8
|
+
SUPPORTED_NON_GEMINI_MODEL_IDS = frozenset(
|
|
9
|
+
{
|
|
10
|
+
"claude-sonnet-4-6",
|
|
11
|
+
"claude-opus-4-6-thinking",
|
|
12
|
+
"gpt-oss-120b-medium",
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
_MAX_OUTPUT_TOKENS_BY_MODEL_ID = {
|
|
17
|
+
"claude-sonnet-4-6": 64000,
|
|
18
|
+
"claude-opus-4-6-thinking": 64000,
|
|
19
|
+
"gpt-oss-120b-medium": 32768,
|
|
20
|
+
}
|
|
21
|
+
_GPT_OSS_MODEL_ID = "gpt-oss-120b-medium"
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"SUPPORTED_NON_GEMINI_MODEL_IDS",
|
|
25
|
+
"is_catalog_model",
|
|
26
|
+
"transform_request",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def is_catalog_model(model_id: str) -> bool:
|
|
31
|
+
"""Return whether a raw catalog entry is supported by the local profile."""
|
|
32
|
+
return isinstance(model_id, str) and (
|
|
33
|
+
model_id.startswith("gemini") or model_id in SUPPORTED_NON_GEMINI_MODEL_IDS
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def transform_request(model_id: str, body: Dict[str, Any]) -> Dict[str, Any]:
|
|
38
|
+
"""Adapt a supported non-Gemini request in place and return the same body."""
|
|
39
|
+
if not isinstance(model_id, str) or not isinstance(body, dict):
|
|
40
|
+
return body
|
|
41
|
+
maximum = _MAX_OUTPUT_TOKENS_BY_MODEL_ID.get(model_id)
|
|
42
|
+
if maximum is None:
|
|
43
|
+
return body
|
|
44
|
+
|
|
45
|
+
_normalize_generation_config(body, maximum, model_id == _GPT_OSS_MODEL_ID)
|
|
46
|
+
_normalize_tool_schemas(body)
|
|
47
|
+
_normalize_tool_call_ids(body)
|
|
48
|
+
return body
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _normalize_generation_config(body: Dict[str, Any], maximum: int, gpt_oss: bool) -> None:
|
|
52
|
+
config = body.get("generationConfig")
|
|
53
|
+
if not isinstance(config, dict):
|
|
54
|
+
config = {}
|
|
55
|
+
|
|
56
|
+
max_output_tokens = _clamp_max_output_tokens(config.get("maxOutputTokens"), maximum)
|
|
57
|
+
if gpt_oss:
|
|
58
|
+
body["generationConfig"] = {"maxOutputTokens": max_output_tokens}
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
config["maxOutputTokens"] = max_output_tokens
|
|
62
|
+
body["generationConfig"] = config
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _clamp_max_output_tokens(value: Any, maximum: int) -> int:
|
|
66
|
+
if isinstance(value, int) and not isinstance(value, bool) and value > 0:
|
|
67
|
+
return min(value, maximum)
|
|
68
|
+
return maximum
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _normalize_tool_schemas(body: Dict[str, Any]) -> None:
|
|
72
|
+
for declaration in _function_declarations(body):
|
|
73
|
+
if "parameters" in declaration:
|
|
74
|
+
declaration["parameters"] = _strip_schema(declaration["parameters"])
|
|
75
|
+
declaration.pop("parametersJsonSchema", None)
|
|
76
|
+
elif "parametersJsonSchema" in declaration:
|
|
77
|
+
declaration["parameters"] = _strip_schema(declaration.pop("parametersJsonSchema"))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _function_declarations(body: Dict[str, Any]) -> Iterator[Dict[str, Any]]:
|
|
81
|
+
tools = body.get("tools")
|
|
82
|
+
if isinstance(tools, dict):
|
|
83
|
+
tool_items = [tools]
|
|
84
|
+
elif isinstance(tools, list):
|
|
85
|
+
tool_items = tools
|
|
86
|
+
else:
|
|
87
|
+
return
|
|
88
|
+
|
|
89
|
+
for tool in tool_items:
|
|
90
|
+
if not isinstance(tool, dict):
|
|
91
|
+
continue
|
|
92
|
+
declarations = tool.get("functionDeclarations")
|
|
93
|
+
if isinstance(declarations, dict):
|
|
94
|
+
declarations = [declarations]
|
|
95
|
+
if not isinstance(declarations, list):
|
|
96
|
+
continue
|
|
97
|
+
for declaration in declarations:
|
|
98
|
+
if isinstance(declaration, dict):
|
|
99
|
+
yield declaration
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _strip_schema(value: Any) -> Any:
|
|
103
|
+
if isinstance(value, dict):
|
|
104
|
+
return {key: _strip_schema(child) for key, child in value.items() if key != "$schema"}
|
|
105
|
+
if isinstance(value, list):
|
|
106
|
+
return [_strip_schema(child) for child in value]
|
|
107
|
+
return value
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _normalize_tool_call_ids(body: Dict[str, Any]) -> None:
|
|
111
|
+
parts = list(_history_parts(body))
|
|
112
|
+
reserved_ids = {
|
|
113
|
+
call_id
|
|
114
|
+
for part in parts
|
|
115
|
+
for call_id in [_existing_id(part.get("functionCall"))]
|
|
116
|
+
if call_id is not None
|
|
117
|
+
}
|
|
118
|
+
pending_call_ids: Dict[str, Deque[str]] = {}
|
|
119
|
+
next_generated_call = 1
|
|
120
|
+
|
|
121
|
+
for part in parts:
|
|
122
|
+
function_call = part.get("functionCall")
|
|
123
|
+
if isinstance(function_call, dict):
|
|
124
|
+
call_id = _existing_id(function_call)
|
|
125
|
+
if call_id is None:
|
|
126
|
+
call_id, next_generated_call = _next_generated_call_id(reserved_ids, next_generated_call)
|
|
127
|
+
function_call["id"] = call_id
|
|
128
|
+
pending_call_ids.setdefault(_function_name(function_call), deque()).append(call_id)
|
|
129
|
+
|
|
130
|
+
function_response = part.get("functionResponse")
|
|
131
|
+
if not isinstance(function_response, dict):
|
|
132
|
+
continue
|
|
133
|
+
pending_for_name = pending_call_ids.get(_function_name(function_response))
|
|
134
|
+
if pending_for_name:
|
|
135
|
+
function_response["id"] = pending_for_name.popleft()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _history_parts(body: Dict[str, Any]) -> Iterator[Dict[str, Any]]:
|
|
139
|
+
contents = body.get("contents")
|
|
140
|
+
if not isinstance(contents, list):
|
|
141
|
+
return
|
|
142
|
+
|
|
143
|
+
for content in contents:
|
|
144
|
+
if not isinstance(content, dict):
|
|
145
|
+
continue
|
|
146
|
+
parts = content.get("parts")
|
|
147
|
+
if not isinstance(parts, list):
|
|
148
|
+
continue
|
|
149
|
+
for part in parts:
|
|
150
|
+
if isinstance(part, dict):
|
|
151
|
+
yield part
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _existing_id(payload: Any) -> Optional[str]:
|
|
155
|
+
if not isinstance(payload, dict):
|
|
156
|
+
return None
|
|
157
|
+
value = payload.get("id")
|
|
158
|
+
return value if isinstance(value, str) and value else None
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _function_name(payload: Dict[str, Any]) -> str:
|
|
162
|
+
name = payload.get("name")
|
|
163
|
+
return name if isinstance(name, str) else ""
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _next_generated_call_id(reserved_ids: Set[str], next_index: int) -> Tuple[str, int]:
|
|
167
|
+
while True:
|
|
168
|
+
candidate = f"acp-tool-{next_index}"
|
|
169
|
+
next_index += 1
|
|
170
|
+
if candidate not in reserved_ids:
|
|
171
|
+
reserved_ids.add(candidate)
|
|
172
|
+
return candidate, next_index
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const PASEO_DAEMON_CONTEXT_OPEN = "[Paseo daemon system context]";
|
|
2
|
+
export declare const PASEO_DAEMON_CONTEXT_CLOSE = "[/Paseo daemon system context]";
|
|
3
|
+
export declare function resolvePaseoHome(environment?: NodeJS.ProcessEnv): string;
|
|
4
|
+
export declare function readPaseoDaemonAppendSystemPrompt(environment?: NodeJS.ProcessEnv): Promise<string>;
|
|
5
|
+
export declare function withPaseoDaemonSystemContext(promptText: string, environment?: NodeJS.ProcessEnv): Promise<string>;
|
|
6
|
+
export declare function wrapPaseoDaemonContextBlock(append: string): string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const MAX_PASEO_APPEND_CHARS = 200_000;
|
|
5
|
+
const PASEO_APPEND_RETRY_ATTEMPTS = 25;
|
|
6
|
+
const PASEO_APPEND_RETRY_DELAY_MS = 20;
|
|
7
|
+
export const PASEO_DAEMON_CONTEXT_OPEN = "[Paseo daemon system context]";
|
|
8
|
+
export const PASEO_DAEMON_CONTEXT_CLOSE = "[/Paseo daemon system context]";
|
|
9
|
+
async function findPaseoAgentState(dir, fileName, depth = 4) {
|
|
10
|
+
if (depth < 0)
|
|
11
|
+
return undefined;
|
|
12
|
+
let entries;
|
|
13
|
+
try {
|
|
14
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
const child = path.join(dir, entry.name);
|
|
21
|
+
if (entry.isFile() && entry.name === fileName)
|
|
22
|
+
return child;
|
|
23
|
+
}
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (!entry.isDirectory())
|
|
26
|
+
continue;
|
|
27
|
+
const found = await findPaseoAgentState(path.join(dir, entry.name), fileName, depth - 1);
|
|
28
|
+
if (found)
|
|
29
|
+
return found;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
function delay(ms) {
|
|
34
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
35
|
+
}
|
|
36
|
+
export function resolvePaseoHome(environment = process.env) {
|
|
37
|
+
const configured = environment.PASEO_HOME?.trim();
|
|
38
|
+
if (configured) {
|
|
39
|
+
if (configured === "~")
|
|
40
|
+
return os.homedir();
|
|
41
|
+
if (configured.startsWith("~/") || configured.startsWith("~\\")) {
|
|
42
|
+
return path.join(os.homedir(), configured.slice(2));
|
|
43
|
+
}
|
|
44
|
+
return configured;
|
|
45
|
+
}
|
|
46
|
+
const homeDir = environment.HOME || os.homedir();
|
|
47
|
+
return homeDir ? path.join(homeDir, ".paseo") : "";
|
|
48
|
+
}
|
|
49
|
+
export async function readPaseoDaemonAppendSystemPrompt(environment = process.env) {
|
|
50
|
+
const home = resolvePaseoHome(environment);
|
|
51
|
+
const agentId = environment.PASEO_AGENT_ID;
|
|
52
|
+
if (!home || !agentId || agentId.includes("/") || agentId.includes("\\"))
|
|
53
|
+
return "";
|
|
54
|
+
for (let attempt = 0; attempt < PASEO_APPEND_RETRY_ATTEMPTS; attempt++) {
|
|
55
|
+
try {
|
|
56
|
+
const statePath = await findPaseoAgentState(path.join(home, "agents"), `${agentId}.json`);
|
|
57
|
+
if (statePath) {
|
|
58
|
+
const state = JSON.parse(await readFile(statePath, "utf8"));
|
|
59
|
+
const append = state.persistence?.metadata?.daemonAppendSystemPrompt;
|
|
60
|
+
if (typeof append === "string" && append.trim()) {
|
|
61
|
+
return append.trim().slice(0, MAX_PASEO_APPEND_CHARS);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Paseo may still be writing the state file. Retry briefly, then fail open.
|
|
67
|
+
}
|
|
68
|
+
if (attempt < PASEO_APPEND_RETRY_ATTEMPTS - 1) {
|
|
69
|
+
await delay(PASEO_APPEND_RETRY_DELAY_MS);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return "";
|
|
73
|
+
}
|
|
74
|
+
export async function withPaseoDaemonSystemContext(promptText, environment = process.env) {
|
|
75
|
+
const append = await readPaseoDaemonAppendSystemPrompt(environment);
|
|
76
|
+
if (!append)
|
|
77
|
+
return promptText;
|
|
78
|
+
return [PASEO_DAEMON_CONTEXT_OPEN, append, PASEO_DAEMON_CONTEXT_CLOSE, "", promptText].join("\n");
|
|
79
|
+
}
|
|
80
|
+
export function wrapPaseoDaemonContextBlock(append) {
|
|
81
|
+
return [PASEO_DAEMON_CONTEXT_OPEN, append, PASEO_DAEMON_CONTEXT_CLOSE].join("\n");
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=paseo-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paseo-context.js","sourceRoot":"","sources":["../../../../ACP Connector/acp/session/paseo-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,sBAAsB,GAAG,OAAO,CAAC;AACvC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AACvC,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAEvC,MAAM,CAAC,MAAM,yBAAyB,GAAG,+BAA+B,CAAC;AACzE,MAAM,CAAC,MAAM,0BAA0B,GAAG,gCAAgC,CAAC;AAE3E,KAAK,UAAU,mBAAmB,CAChC,GAAW,EACX,QAAgB,EAChB,KAAK,GAAG,CAAC;IAET,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;IAC9D,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QACnC,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QACzF,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAW,GAAsB,OAAO,CAAC,GAAG;IAC3E,MAAM,UAAU,GAAG,WAAW,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;IAClD,IAAI,UAAU,EAAE,CAAC;QACf,IAAI,UAAU,KAAK,GAAG;YAAE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;QAC5C,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;IACjD,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,WAAW,GAAsB,OAAO,CAAC,GAAG;IAE5C,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC;IAC3C,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpF,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,2BAA2B,EAAE,OAAO,EAAE,EAAE,CAAC;QACvE,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,GAAG,OAAO,OAAO,CAAC,CAAC;YAC1F,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAEzD,CAAC;gBACF,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,EAAE,QAAQ,EAAE,wBAAwB,CAAC;gBACrE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;oBAChD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,4EAA4E;QAC9E,CAAC;QACD,IAAI,OAAO,GAAG,2BAA2B,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,UAAkB,EAClB,WAAW,GAAsB,OAAO,CAAC,GAAG;IAE5C,MAAM,MAAM,GAAG,MAAM,iCAAiC,CAAC,WAAW,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM;QAAE,OAAO,UAAU,CAAC;IAC/B,OAAO,CAAC,yBAAyB,EAAE,MAAM,EAAE,0BAA0B,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAAc;IACxD,OAAO,CAAC,yBAAyB,EAAE,MAAM,EAAE,0BAA0B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/** Thrown when a claim is aborted; unwinds the turn pipeline to its reporter. */
|
|
2
|
+
export declare class TurnCancelled extends Error {
|
|
3
|
+
constructor(message?: string);
|
|
4
|
+
}
|
|
5
|
+
export declare function isTurnCancelled(error: unknown): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Run `fn` for an abort signal, now or later. Plain `addEventListener` never
|
|
8
|
+
* fires for a signal that is already aborted, which repeatedly produced turns
|
|
9
|
+
* that ran after they had been cancelled.
|
|
10
|
+
*/
|
|
11
|
+
export declare function onAbort(signal: AbortSignal, fn: () => void): () => void;
|
|
12
|
+
export type TurnKind = "foreground" | "queued" | "steer";
|
|
13
|
+
/** A request's ownership of (or reservation on) the session's single turn slot. */
|
|
14
|
+
export declare class TurnClaim {
|
|
15
|
+
readonly kind: TurnKind;
|
|
16
|
+
/**
|
|
17
|
+
* For claimed queued prompts, the client-visible queue id. Lets a targeted
|
|
18
|
+
* `session/cancel` find the turn its queued item grew into, so it aborts
|
|
19
|
+
* exactly that claim instead of falling back to a session-wide abort.
|
|
20
|
+
*/
|
|
21
|
+
readonly tag?: string;
|
|
22
|
+
private readonly controller;
|
|
23
|
+
private isReleased;
|
|
24
|
+
constructor(kind: TurnKind, parent?: AbortSignal, tag?: string);
|
|
25
|
+
get signal(): AbortSignal;
|
|
26
|
+
get aborted(): boolean;
|
|
27
|
+
get released(): boolean;
|
|
28
|
+
abort(): void;
|
|
29
|
+
throwIfAborted(): void;
|
|
30
|
+
/** @internal — the scheduler marks a claim finished exactly once. */
|
|
31
|
+
markReleased(): boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Await `promise`, rejecting with `TurnCancelled` as soon as `signal` aborts.
|
|
35
|
+
*
|
|
36
|
+
* The single implementation behind invariant I4: every client-bound delivery
|
|
37
|
+
* goes through here (directly, or via `raceClaim` for turn claims), so a
|
|
38
|
+
* client transport that never settles unwinds on cancel/close instead of
|
|
39
|
+
* pinning the turn slot or the queue-preparation chain.
|
|
40
|
+
*/
|
|
41
|
+
export declare function raceSignal<T>(promise: Promise<T>, signal: AbortSignal): Promise<T>;
|
|
42
|
+
/** Await `promise`, rejecting as soon as `claim` is aborted. */
|
|
43
|
+
export declare function raceClaim<T>(promise: Promise<T>, claim: TurnClaim): Promise<T>;
|
|
44
|
+
/** Lazily attach a scheduler to a session-like object. */
|
|
45
|
+
export declare function turnsOf(session: {
|
|
46
|
+
turns?: TurnScheduler;
|
|
47
|
+
}): TurnScheduler;
|
|
48
|
+
export declare class TurnScheduler {
|
|
49
|
+
private active?;
|
|
50
|
+
/** Steer reservations in FIFO order; the head is next to take the slot. */
|
|
51
|
+
private reservations;
|
|
52
|
+
private waiters;
|
|
53
|
+
private closed;
|
|
54
|
+
/** True when a turn is running or a steer has reserved the next turn. */
|
|
55
|
+
busy(): boolean;
|
|
56
|
+
get activeClaim(): TurnClaim | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Take the slot for a request that found the session idle. Synchronous by
|
|
59
|
+
* design: no await may separate the busy check from the claim (I1).
|
|
60
|
+
*/
|
|
61
|
+
claimIdle(kind: Exclude<TurnKind, "steer">, parent?: AbortSignal, tag?: string): TurnClaim;
|
|
62
|
+
/**
|
|
63
|
+
* Reserve the next turn for a steer. Synchronous, so the claim — and its
|
|
64
|
+
* abort controller — exist before the first await (I1, I2). The reservation
|
|
65
|
+
* keeps the session `busy()`, so no queued follow-up can slip in front.
|
|
66
|
+
*/
|
|
67
|
+
reserveSteer(parent?: AbortSignal): TurnClaim;
|
|
68
|
+
/**
|
|
69
|
+
* Wait for `claim` to reach the head of the reservation queue, stop whatever
|
|
70
|
+
* is running, and hand it the slot. Throws `TurnCancelled` if the claim is
|
|
71
|
+
* aborted at any point, including while the backend is being killed.
|
|
72
|
+
*
|
|
73
|
+
* A reservation stays in the queue until it is *released*, not merely until
|
|
74
|
+
* it is promoted. Otherwise a later steer would reach the head while an
|
|
75
|
+
* earlier one was running and displace it before it ever reached the backend.
|
|
76
|
+
*/
|
|
77
|
+
promote(claim: TurnClaim, cancelActive: () => Promise<void>): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Finish a claim. Idempotent, and safe to call from a `finally` on any exit
|
|
80
|
+
* path — success, cancellation, or setup failure.
|
|
81
|
+
*/
|
|
82
|
+
release(claim: TurnClaim): void;
|
|
83
|
+
/** Abort every live claim (`session/cancel`). Queued items are untouched. */
|
|
84
|
+
abortAll(): void;
|
|
85
|
+
/** Abort everything and refuse further claims (close / delete / evict). */
|
|
86
|
+
close(): void;
|
|
87
|
+
private change;
|
|
88
|
+
/** Resolve on the next ownership change, or reject if `claim` is aborted. */
|
|
89
|
+
private nextChange;
|
|
90
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// Turn ownership for a single ACP session.
|
|
2
|
+
//
|
|
3
|
+
// One session may only run one prompt turn against the agy backend at a time.
|
|
4
|
+
// Requests compete for that slot in three ways: an idle request claims it
|
|
5
|
+
// directly, a `queue` request waits in FIFO, and a `steer` request reserves it
|
|
6
|
+
// and displaces whatever is running.
|
|
7
|
+
//
|
|
8
|
+
// The invariants below exist because ad-hoc ownership flags spread across the
|
|
9
|
+
// prompt handlers made every `await` a window where the session could be
|
|
10
|
+
// half-owned, and every such window was a cancellation bug:
|
|
11
|
+
//
|
|
12
|
+
// I1. A claim is one object that exists from admission until the turn is fully
|
|
13
|
+
// finished — including a steer's wait for the previous turn to stop. There
|
|
14
|
+
// is no phase where a request owns the session but has no claim.
|
|
15
|
+
// I2. Every claim carries its AbortController from the moment it is created,
|
|
16
|
+
// so cancel/close/evict always have something to abort in every phase.
|
|
17
|
+
// I3. Cancellation unwinds by throwing (`TurnCancelled`), not by polling a
|
|
18
|
+
// flag after each await. Callers cannot forget to re-check.
|
|
19
|
+
// I4. Every client-bound delivery is raced against the turn's claim (or a
|
|
20
|
+
// queued item's controller). agy's prompt loop awaits each update
|
|
21
|
+
// callback, so a client transport that never settles would otherwise pin
|
|
22
|
+
// the slot forever — killing the backend cannot settle a wedged notify.
|
|
23
|
+
/** Thrown when a claim is aborted; unwinds the turn pipeline to its reporter. */
|
|
24
|
+
export class TurnCancelled extends Error {
|
|
25
|
+
constructor(message = "turn cancelled") {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "TurnCancelled";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function isTurnCancelled(error) {
|
|
31
|
+
const name = error?.name;
|
|
32
|
+
return error instanceof TurnCancelled || name === "TurnCancelled" || name === "AbortError";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Run `fn` for an abort signal, now or later. Plain `addEventListener` never
|
|
36
|
+
* fires for a signal that is already aborted, which repeatedly produced turns
|
|
37
|
+
* that ran after they had been cancelled.
|
|
38
|
+
*/
|
|
39
|
+
export function onAbort(signal, fn) {
|
|
40
|
+
if (signal.aborted) {
|
|
41
|
+
fn();
|
|
42
|
+
return () => { };
|
|
43
|
+
}
|
|
44
|
+
signal.addEventListener("abort", fn, { once: true });
|
|
45
|
+
return () => signal.removeEventListener("abort", fn);
|
|
46
|
+
}
|
|
47
|
+
/** A request's ownership of (or reservation on) the session's single turn slot. */
|
|
48
|
+
export class TurnClaim {
|
|
49
|
+
kind;
|
|
50
|
+
/**
|
|
51
|
+
* For claimed queued prompts, the client-visible queue id. Lets a targeted
|
|
52
|
+
* `session/cancel` find the turn its queued item grew into, so it aborts
|
|
53
|
+
* exactly that claim instead of falling back to a session-wide abort.
|
|
54
|
+
*/
|
|
55
|
+
tag;
|
|
56
|
+
controller = new AbortController();
|
|
57
|
+
isReleased = false;
|
|
58
|
+
constructor(kind, parent, tag) {
|
|
59
|
+
this.kind = kind;
|
|
60
|
+
this.tag = tag;
|
|
61
|
+
// A request-scoped signal (v1 `session/prompt` cancellation) folds into the
|
|
62
|
+
// claim, so downstream code only ever consults one signal.
|
|
63
|
+
if (parent)
|
|
64
|
+
onAbort(parent, () => this.abort());
|
|
65
|
+
}
|
|
66
|
+
get signal() {
|
|
67
|
+
return this.controller.signal;
|
|
68
|
+
}
|
|
69
|
+
get aborted() {
|
|
70
|
+
return this.controller.signal.aborted;
|
|
71
|
+
}
|
|
72
|
+
get released() {
|
|
73
|
+
return this.isReleased;
|
|
74
|
+
}
|
|
75
|
+
abort() {
|
|
76
|
+
if (!this.controller.signal.aborted)
|
|
77
|
+
this.controller.abort(new TurnCancelled());
|
|
78
|
+
}
|
|
79
|
+
throwIfAborted() {
|
|
80
|
+
if (this.aborted)
|
|
81
|
+
throw new TurnCancelled();
|
|
82
|
+
}
|
|
83
|
+
/** @internal — the scheduler marks a claim finished exactly once. */
|
|
84
|
+
markReleased() {
|
|
85
|
+
if (this.isReleased)
|
|
86
|
+
return false;
|
|
87
|
+
this.isReleased = true;
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Await `promise`, rejecting with `TurnCancelled` as soon as `signal` aborts.
|
|
93
|
+
*
|
|
94
|
+
* The single implementation behind invariant I4: every client-bound delivery
|
|
95
|
+
* goes through here (directly, or via `raceClaim` for turn claims), so a
|
|
96
|
+
* client transport that never settles unwinds on cancel/close instead of
|
|
97
|
+
* pinning the turn slot or the queue-preparation chain.
|
|
98
|
+
*/
|
|
99
|
+
export function raceSignal(promise, signal) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
if (signal.aborted) {
|
|
102
|
+
reject(new TurnCancelled());
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const off = onAbort(signal, () => reject(new TurnCancelled()));
|
|
106
|
+
promise.then((value) => {
|
|
107
|
+
off();
|
|
108
|
+
resolve(value);
|
|
109
|
+
}, (error) => {
|
|
110
|
+
off();
|
|
111
|
+
reject(error);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/** Await `promise`, rejecting as soon as `claim` is aborted. */
|
|
116
|
+
export function raceClaim(promise, claim) {
|
|
117
|
+
return raceSignal(promise, claim.signal);
|
|
118
|
+
}
|
|
119
|
+
/** Lazily attach a scheduler to a session-like object. */
|
|
120
|
+
export function turnsOf(session) {
|
|
121
|
+
return (session.turns ??= new TurnScheduler());
|
|
122
|
+
}
|
|
123
|
+
export class TurnScheduler {
|
|
124
|
+
active;
|
|
125
|
+
/** Steer reservations in FIFO order; the head is next to take the slot. */
|
|
126
|
+
reservations = [];
|
|
127
|
+
waiters = new Set();
|
|
128
|
+
closed = false;
|
|
129
|
+
/** True when a turn is running or a steer has reserved the next turn. */
|
|
130
|
+
busy() {
|
|
131
|
+
return this.active !== undefined || this.reservations.length > 0;
|
|
132
|
+
}
|
|
133
|
+
get activeClaim() {
|
|
134
|
+
return this.active;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Take the slot for a request that found the session idle. Synchronous by
|
|
138
|
+
* design: no await may separate the busy check from the claim (I1).
|
|
139
|
+
*/
|
|
140
|
+
claimIdle(kind, parent, tag) {
|
|
141
|
+
if (this.busy()) {
|
|
142
|
+
// Callers must check `busy()` with no await in between; overwriting the
|
|
143
|
+
// slot here would silently orphan a running turn.
|
|
144
|
+
throw new Error("cannot claim a busy session turn slot");
|
|
145
|
+
}
|
|
146
|
+
const claim = new TurnClaim(kind, parent, tag);
|
|
147
|
+
this.active = claim;
|
|
148
|
+
if (this.closed)
|
|
149
|
+
claim.abort();
|
|
150
|
+
return claim;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Reserve the next turn for a steer. Synchronous, so the claim — and its
|
|
154
|
+
* abort controller — exist before the first await (I1, I2). The reservation
|
|
155
|
+
* keeps the session `busy()`, so no queued follow-up can slip in front.
|
|
156
|
+
*/
|
|
157
|
+
reserveSteer(parent) {
|
|
158
|
+
const claim = new TurnClaim("steer", parent);
|
|
159
|
+
this.reservations.push(claim);
|
|
160
|
+
if (this.closed)
|
|
161
|
+
claim.abort();
|
|
162
|
+
return claim;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Wait for `claim` to reach the head of the reservation queue, stop whatever
|
|
166
|
+
* is running, and hand it the slot. Throws `TurnCancelled` if the claim is
|
|
167
|
+
* aborted at any point, including while the backend is being killed.
|
|
168
|
+
*
|
|
169
|
+
* A reservation stays in the queue until it is *released*, not merely until
|
|
170
|
+
* it is promoted. Otherwise a later steer would reach the head while an
|
|
171
|
+
* earlier one was running and displace it before it ever reached the backend.
|
|
172
|
+
*/
|
|
173
|
+
async promote(claim, cancelActive) {
|
|
174
|
+
claim.throwIfAborted();
|
|
175
|
+
while (this.reservations[0] !== claim) {
|
|
176
|
+
if (!this.reservations.includes(claim))
|
|
177
|
+
throw new TurnCancelled();
|
|
178
|
+
await this.nextChange(claim);
|
|
179
|
+
}
|
|
180
|
+
const displaced = this.active;
|
|
181
|
+
if (displaced) {
|
|
182
|
+
displaced.abort();
|
|
183
|
+
// Cancellable while the backend shuts down: a stop arriving during a slow
|
|
184
|
+
// kill must not be swallowed and then followed by the replacement turn.
|
|
185
|
+
await raceClaim(cancelActive(), claim);
|
|
186
|
+
while (this.active)
|
|
187
|
+
await this.nextChange(claim);
|
|
188
|
+
}
|
|
189
|
+
claim.throwIfAborted();
|
|
190
|
+
if (this.reservations[0] !== claim)
|
|
191
|
+
throw new TurnCancelled();
|
|
192
|
+
this.active = claim;
|
|
193
|
+
this.change();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Finish a claim. Idempotent, and safe to call from a `finally` on any exit
|
|
197
|
+
* path — success, cancellation, or setup failure.
|
|
198
|
+
*/
|
|
199
|
+
release(claim) {
|
|
200
|
+
if (!claim.markReleased())
|
|
201
|
+
return;
|
|
202
|
+
if (this.active === claim)
|
|
203
|
+
this.active = undefined;
|
|
204
|
+
const idx = this.reservations.indexOf(claim);
|
|
205
|
+
if (idx >= 0)
|
|
206
|
+
this.reservations.splice(idx, 1);
|
|
207
|
+
this.change();
|
|
208
|
+
}
|
|
209
|
+
/** Abort every live claim (`session/cancel`). Queued items are untouched. */
|
|
210
|
+
abortAll() {
|
|
211
|
+
this.active?.abort();
|
|
212
|
+
for (const reservation of [...this.reservations])
|
|
213
|
+
reservation.abort();
|
|
214
|
+
}
|
|
215
|
+
/** Abort everything and refuse further claims (close / delete / evict). */
|
|
216
|
+
close() {
|
|
217
|
+
this.closed = true;
|
|
218
|
+
this.abortAll();
|
|
219
|
+
this.change();
|
|
220
|
+
}
|
|
221
|
+
change() {
|
|
222
|
+
const pending = [...this.waiters];
|
|
223
|
+
this.waiters.clear();
|
|
224
|
+
for (const waiter of pending)
|
|
225
|
+
waiter();
|
|
226
|
+
}
|
|
227
|
+
/** Resolve on the next ownership change, or reject if `claim` is aborted. */
|
|
228
|
+
nextChange(claim) {
|
|
229
|
+
return new Promise((resolve, reject) => {
|
|
230
|
+
if (claim.aborted) {
|
|
231
|
+
reject(new TurnCancelled());
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
let off = () => { };
|
|
235
|
+
const waiter = () => {
|
|
236
|
+
off();
|
|
237
|
+
resolve();
|
|
238
|
+
};
|
|
239
|
+
this.waiters.add(waiter);
|
|
240
|
+
off = onAbort(claim.signal, () => {
|
|
241
|
+
this.waiters.delete(waiter);
|
|
242
|
+
reject(new TurnCancelled());
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=turn-scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-scheduler.js","sourceRoot":"","sources":["../../../../ACP Connector/acp/session/turn-scheduler.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,+EAA+E;AAC/E,qCAAqC;AACrC,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,4DAA4D;AAC5D,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,sEAAsE;AACtE,8EAA8E;AAC9E,4EAA4E;AAC5E,4EAA4E;AAC5E,iEAAiE;AACjE,2EAA2E;AAC3E,uEAAuE;AACvE,8EAA8E;AAC9E,6EAA6E;AAE7E,iFAAiF;AACjF,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,GAAG,gBAAgB;QACpC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,MAAM,IAAI,GAAI,KAA+C,EAAE,IAAI,CAAC;IACpE,OAAO,KAAK,YAAY,aAAa,IAAI,IAAI,KAAK,eAAe,IAAI,IAAI,KAAK,YAAY,CAAC;AAC7F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,MAAmB,EAAE,EAAc;IACzD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,EAAE,EAAE,CAAC;QACL,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACvD,CAAC;AAID,mFAAmF;AACnF,MAAM,OAAO,SAAS;IACX,IAAI,CAAW;IACxB;;;;OAIG;IACM,GAAG,CAAU;IACL,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IAC5C,UAAU,GAAG,KAAK,CAAC;IAE3B,YAAY,IAAc,EAAE,MAAoB,EAAE,GAAY;QAC5D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,4EAA4E;QAC5E,2DAA2D;QAC3D,IAAI,MAAM;YAAE,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAChC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;IACxC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO;YAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,cAAc;QACZ,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,aAAa,EAAE,CAAC;IAC9C,CAAC;IAED,qEAAqE;IACrE,YAAY;QACV,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAI,OAAmB,EAAE,MAAmB;IACpE,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE;YACR,GAAG,EAAE,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;YACR,GAAG,EAAE,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,SAAS,CAAI,OAAmB,EAAE,KAAgB;IAChE,OAAO,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,OAAO,CAAC,OAAkC;IACxD,OAAO,CAAC,OAAO,CAAC,KAAK,KAAK,IAAI,aAAa,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,OAAO,aAAa;IAChB,MAAM,CAAa;IAC3B,2EAA2E;IACnE,YAAY,GAAgB,EAAE,CAAC;IAC/B,OAAO,GAAG,IAAI,GAAG,EAAc,CAAC;IAChC,MAAM,GAAG,KAAK,CAAC;IAEvB,yEAAyE;IACzE,IAAI;QACF,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,SAAS,CAAC,IAAgC,EAAE,MAAoB,EAAE,GAAY;QAC5E,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YAChB,wEAAwE;YACxE,kDAAkD;YAClD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,MAAoB;QAC/B,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CAAC,KAAgB,EAAE,YAAiC;QAC/D,KAAK,CAAC,cAAc,EAAE,CAAC;QAEvB,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,aAAa,EAAE,CAAC;YAClE,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;QAC9B,IAAI,SAAS,EAAE,CAAC;YACd,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,0EAA0E;YAC1E,wEAAwE;YACxE,MAAM,SAAS,CAAC,YAAY,EAAE,EAAE,KAAK,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACnD,CAAC;QAED,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,KAAK;YAAE,MAAM,IAAI,aAAa,EAAE,CAAC;QAC9D,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,KAAgB;QACtB,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE;YAAE,OAAO;QAClC,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK;YAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,GAAG,IAAI,CAAC;YAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,6EAA6E;IAC7E,QAAQ;QACN,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;QACrB,KAAK,MAAM,WAAW,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;YAAE,WAAW,CAAC,KAAK,EAAE,CAAC;IACxE,CAAC;IAED,2EAA2E;IAC3E,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAEO,MAAM;QACZ,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,MAAM,EAAE,CAAC;IACzC,CAAC;IAED,6EAA6E;IACrE,UAAU,CAAC,KAAgB;QACjC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;gBAC5B,OAAO;YACT,CAAC;YACD,IAAI,GAAG,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;YACnB,MAAM,MAAM,GAAG,GAAG,EAAE;gBAClB,GAAG,EAAE,CAAC;gBACN,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACzB,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE;gBAC/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC5B,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request-scoped stdin write fence used by Admission around one official
|
|
3
|
+
* `session/prompt` dispatch. The official kernel owns process creation; this
|
|
4
|
+
* boundary only sequences prepare → write → settle.
|
|
5
|
+
*/
|
|
6
|
+
export interface AgyAdmissionDispatchBoundary {
|
|
7
|
+
prepare(processId: number): void;
|
|
8
|
+
beforePromptWrite(): void;
|
|
9
|
+
afterPromptWrite(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare class AgyCliError extends Error {
|
|
12
|
+
readonly command: string[];
|
|
13
|
+
readonly exitCode: number | null;
|
|
14
|
+
readonly stderr: string;
|
|
15
|
+
constructor(message: string, command: string[], exitCode: number | null, stderr: string);
|
|
16
|
+
}
|
|
17
|
+
/** Provider failure proven terminal by the official kernel or a classified 5xx. */
|
|
18
|
+
export declare class AgyTerminalProviderError extends AgyCliError {
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class AgyCliError extends Error {
|
|
2
|
+
command;
|
|
3
|
+
exitCode;
|
|
4
|
+
stderr;
|
|
5
|
+
constructor(message, command, exitCode, stderr) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "AgyCliError";
|
|
8
|
+
this.command = command;
|
|
9
|
+
this.exitCode = exitCode;
|
|
10
|
+
this.stderr = stderr;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Provider failure proven terminal by the official kernel or a classified 5xx. */
|
|
14
|
+
export class AgyTerminalProviderError extends AgyCliError {
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=dispatch-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-boundary.js","sourceRoot":"","sources":["../../../ACP Connector/admission/dispatch-boundary.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,OAAO,CAAW;IAClB,QAAQ,CAAgB;IACxB,MAAM,CAAS;IAExB,YAAY,OAAe,EAAE,OAAiB,EAAE,QAAuB,EAAE,MAAc;QACrF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,mFAAmF;AACnF,MAAM,OAAO,wBAAyB,SAAQ,WAAW;CAAG"}
|