@anhlp/alp-runtime 0.0.0-beta.2 → 0.0.1-beta.3
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/dist/claude-transport.d.ts +3 -0
- package/dist/claude-transport.js +59 -8
- package/dist/contracts.d.ts +2 -1
- package/dist/runtime-context.d.ts +1 -1
- package/dist/runtime-context.js +1 -1
- package/dist/runtime.js +244 -122
- package/dist/session-config.d.ts +24 -0
- package/dist/session-config.js +3 -3
- package/dist/session-state.d.ts +8 -1
- package/dist/tool-detail.js +4 -1
- package/dist/tools.d.ts +8 -0
- package/dist/tools.js +7 -5
- package/package.json +3 -3
- package/src/claude-transport.ts +64 -8
- package/src/contracts.ts +2 -2
- package/src/runtime-context.ts +2 -2
- package/src/runtime.ts +261 -115
- package/src/session-config.ts +5 -2
- package/src/session-state.ts +8 -1
- package/src/tool-detail.ts +4 -1
- package/src/tools.ts +6 -4
|
@@ -114,6 +114,7 @@ export declare class ClaudeTransport {
|
|
|
114
114
|
private activeTurn?;
|
|
115
115
|
private closed;
|
|
116
116
|
private assistantText;
|
|
117
|
+
private streamingMessage?;
|
|
117
118
|
private toolCalls;
|
|
118
119
|
/** The last rate limit Claude reported, and whether the running turn hit one. */
|
|
119
120
|
private rateLimit?;
|
|
@@ -165,6 +166,8 @@ export declare class ClaudeTransport {
|
|
|
165
166
|
private consume;
|
|
166
167
|
private handle;
|
|
167
168
|
private emit;
|
|
169
|
+
private assistantState;
|
|
170
|
+
private clearAssistantText;
|
|
168
171
|
private fail;
|
|
169
172
|
close(): Promise<void>;
|
|
170
173
|
}
|
package/dist/claude-transport.js
CHANGED
|
@@ -51,12 +51,14 @@ var toolShapes = {
|
|
|
51
51
|
body: z.string().min(1).max(2e4),
|
|
52
52
|
roles: z.array(z.string().min(1)).min(1).max(10),
|
|
53
53
|
lessons: z.array(z.string().min(1).max(600)).max(50).optional(),
|
|
54
|
-
replace: z.boolean().optional()
|
|
54
|
+
replace: z.boolean().optional(),
|
|
55
|
+
requestId: z.string().min(1).max(100).optional()
|
|
55
56
|
},
|
|
56
57
|
alp_issue: {
|
|
57
58
|
action: z.enum(["search", "create", "comment"]),
|
|
58
59
|
target: z.enum(["project", "alp"]),
|
|
59
60
|
query: z.string().min(1).max(200).optional(),
|
|
61
|
+
requestId: z.string().min(1).max(100).optional(),
|
|
60
62
|
title: z.string().min(1).max(200).optional(),
|
|
61
63
|
body: z.string().min(1).max(2e4).optional(),
|
|
62
64
|
issue: z.number().int().positive().optional(),
|
|
@@ -285,6 +287,7 @@ var ClaudeTransport = class {
|
|
|
285
287
|
activeTurn;
|
|
286
288
|
closed = false;
|
|
287
289
|
assistantText = /* @__PURE__ */ new Map();
|
|
290
|
+
streamingMessage;
|
|
288
291
|
toolCalls = /* @__PURE__ */ new Map();
|
|
289
292
|
/** The last rate limit Claude reported, and whether the running turn hit one. */
|
|
290
293
|
rateLimit;
|
|
@@ -353,6 +356,7 @@ var ClaudeTransport = class {
|
|
|
353
356
|
return {};
|
|
354
357
|
}
|
|
355
358
|
if (method === "thread/start" || method === "thread/resume" || method === "thread/fork") {
|
|
359
|
+
this.clearAssistantText();
|
|
356
360
|
this.config = params;
|
|
357
361
|
this.threadId = method === "thread/resume" ? params.threadId : randomUUID();
|
|
358
362
|
await this.start(method === "thread/start" ? void 0 : { resume: params.threadId, fork: method === "thread/fork" });
|
|
@@ -366,7 +370,10 @@ var ClaudeTransport = class {
|
|
|
366
370
|
if (method === "turn/start" || method === "turn/steer") {
|
|
367
371
|
if (!this.query) throw new Error("Claude thread is not initialized");
|
|
368
372
|
const turnId = method === "turn/steer" ? params.expectedTurnId : randomUUID();
|
|
369
|
-
if (method === "turn/start")
|
|
373
|
+
if (method === "turn/start") {
|
|
374
|
+
this.clearAssistantText();
|
|
375
|
+
this.activeTurn = turnId;
|
|
376
|
+
}
|
|
370
377
|
this.input.push({
|
|
371
378
|
type: "user",
|
|
372
379
|
message: {
|
|
@@ -380,6 +387,7 @@ var ClaudeTransport = class {
|
|
|
380
387
|
return method === "turn/start" ? { turn: { id: turnId } } : {};
|
|
381
388
|
}
|
|
382
389
|
if (method === "turn/interrupt") {
|
|
390
|
+
this.streamingMessage = void 0;
|
|
383
391
|
await this.query?.interrupt();
|
|
384
392
|
return {};
|
|
385
393
|
}
|
|
@@ -483,7 +491,7 @@ var ClaudeTransport = class {
|
|
|
483
491
|
...plugins.length ? { plugins } : {},
|
|
484
492
|
persistSession: !config.ephemeral,
|
|
485
493
|
promptSuggestions: false,
|
|
486
|
-
includePartialMessages:
|
|
494
|
+
includePartialMessages: true,
|
|
487
495
|
...from ? { resume: from.resume, ...from.fork ? { forkSession: true, sessionId: this.threadId } : {} } : { sessionId: this.threadId },
|
|
488
496
|
// Explicit native path avoids SDK optional binaries inside Electron app.asar.
|
|
489
497
|
pathToClaudeCodeExecutable: this.command
|
|
@@ -521,15 +529,42 @@ var ClaudeTransport = class {
|
|
|
521
529
|
if (!this.closed) this.fail(new Error("Claude session exited"));
|
|
522
530
|
}
|
|
523
531
|
handle(message) {
|
|
532
|
+
if (this.closed) return;
|
|
524
533
|
if (message.type === "rate_limit_event") {
|
|
525
534
|
this.rateLimit = message.rate_limit_info;
|
|
526
535
|
this.emit("account/rateLimits/updated", { claude: message.rate_limit_info });
|
|
527
536
|
return;
|
|
528
537
|
}
|
|
529
|
-
|
|
538
|
+
const streamStart = message.type === "stream_event" && message.event?.type === "message_start";
|
|
539
|
+
if ((message.type === "assistant" || streamStart) && !message.parent_tool_use_id && !this.activeTurn) {
|
|
530
540
|
this.activeTurn = randomUUID();
|
|
531
541
|
this.emit("turn/started", { threadId: this.threadId, turn: { id: this.activeTurn } });
|
|
532
542
|
}
|
|
543
|
+
if (message.type === "stream_event") {
|
|
544
|
+
if (message.parent_tool_use_id) return;
|
|
545
|
+
const event = message.event;
|
|
546
|
+
if (event.type === "message_start") {
|
|
547
|
+
this.streamingMessage = event.message.id;
|
|
548
|
+
} else if (event.type === "message_stop") {
|
|
549
|
+
this.streamingMessage = void 0;
|
|
550
|
+
} else if (this.streamingMessage) {
|
|
551
|
+
const id = this.streamingMessage;
|
|
552
|
+
const state = this.assistantState(id);
|
|
553
|
+
let delta;
|
|
554
|
+
if (event.type === "content_block_start" && event.content_block.type === "text") {
|
|
555
|
+
state.blocks.set(event.index, { text: event.content_block.text, final: false });
|
|
556
|
+
delta = event.content_block.text;
|
|
557
|
+
} else if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
|
|
558
|
+
const block = state.blocks.get(event.index);
|
|
559
|
+
if (block && !block.final) {
|
|
560
|
+
block.text += event.delta.text;
|
|
561
|
+
delta = event.delta.text;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (delta) this.emit("item/agentMessage/delta", { threadId: this.threadId, turnId: this.activeTurn, itemId: id, delta });
|
|
565
|
+
}
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
533
568
|
if (message.type === "assistant" && message.error === "rate_limit") this.limitedTurn = true;
|
|
534
569
|
if (message.type === "system" && (message.subtype === "status" || message.subtype === "compact_boundary")) {
|
|
535
570
|
const system = message;
|
|
@@ -567,14 +602,18 @@ var ClaudeTransport = class {
|
|
|
567
602
|
if (windows.length && !this.compactAt) this.contextWindow = Math.max(...windows);
|
|
568
603
|
}
|
|
569
604
|
if (message.type === "assistant" && !message.parent_tool_use_id) {
|
|
605
|
+
const id = message.message.id;
|
|
606
|
+
const state = this.assistantState(id);
|
|
607
|
+
if (message.uuid && state.seen.has(message.uuid)) return;
|
|
608
|
+
if (message.uuid) state.seen.add(message.uuid);
|
|
570
609
|
for (const block of message.message.content) {
|
|
571
610
|
if (block.type === "text") {
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
|
|
611
|
+
const pending = [...state.blocks.entries()].sort(([a], [b]) => a - b).find(([, value]) => !value.final);
|
|
612
|
+
const index = pending?.[0] ?? Math.max(-1, ...state.blocks.keys()) + 1;
|
|
613
|
+
state.blocks.set(index, { text: block.text, final: true });
|
|
575
614
|
this.emit("item/completed", {
|
|
576
615
|
threadId: this.threadId,
|
|
577
|
-
item: { type: "agentMessage", id, text }
|
|
616
|
+
item: { type: "agentMessage", id, text: [...state.blocks.entries()].sort(([a], [b]) => a - b).map(([, block2]) => block2.text).join("") }
|
|
578
617
|
});
|
|
579
618
|
} else if (block.type === "tool_use") {
|
|
580
619
|
const command = block.name === "Bash" ? String(block.input?.command ?? "") : `${block.name} ${JSON.stringify(block.input ?? {})}`;
|
|
@@ -623,6 +662,7 @@ var ClaudeTransport = class {
|
|
|
623
662
|
}
|
|
624
663
|
return;
|
|
625
664
|
}
|
|
665
|
+
if (message.type === "result") this.clearAssistantText();
|
|
626
666
|
if (message.type === "result" && this.activeTurn) {
|
|
627
667
|
const turnId = this.activeTurn;
|
|
628
668
|
this.activeTurn = void 0;
|
|
@@ -645,14 +685,25 @@ var ClaudeTransport = class {
|
|
|
645
685
|
emit(method, params) {
|
|
646
686
|
for (const listener of this.listeners) listener(method, params);
|
|
647
687
|
}
|
|
688
|
+
assistantState(id) {
|
|
689
|
+
let state = this.assistantText.get(id);
|
|
690
|
+
if (!state) this.assistantText.set(id, state = { blocks: /* @__PURE__ */ new Map(), seen: /* @__PURE__ */ new Set() });
|
|
691
|
+
return state;
|
|
692
|
+
}
|
|
693
|
+
clearAssistantText() {
|
|
694
|
+
this.streamingMessage = void 0;
|
|
695
|
+
this.assistantText.clear();
|
|
696
|
+
}
|
|
648
697
|
fail(value) {
|
|
649
698
|
if (this.closed) return;
|
|
699
|
+
this.clearAssistantText();
|
|
650
700
|
const error = value instanceof Error ? value : new Error(String(value));
|
|
651
701
|
for (const listener of this.failures) listener(error);
|
|
652
702
|
}
|
|
653
703
|
async close() {
|
|
654
704
|
if (this.closed) return;
|
|
655
705
|
this.closed = true;
|
|
706
|
+
this.clearAssistantText();
|
|
656
707
|
this.input.close();
|
|
657
708
|
this.query?.close();
|
|
658
709
|
await this.pump?.catch(() => {
|
package/dist/contracts.d.ts
CHANGED
|
@@ -146,9 +146,10 @@ export type AlpRuntime = {
|
|
|
146
146
|
}, question: string): Promise<RecallAnswer>;
|
|
147
147
|
/** Assignments an earlier alpd left running, which recover() can continue once their root is open again. */
|
|
148
148
|
recoverable(): LiveEntry[];
|
|
149
|
-
/** Continues
|
|
149
|
+
/** Continues work in a reopened tree. continueRoot resumes its running turn; parkedRoot restores its held continuation intent. */
|
|
150
150
|
recover(rootId: string, options?: {
|
|
151
151
|
continueRoot?: boolean;
|
|
152
|
+
parkedRoot?: string;
|
|
152
153
|
}): Promise<RecoveryOutcome[]>;
|
|
153
154
|
/** Gives up the assignments of a tree whose root cannot be opened again: their tasks go back to open. */
|
|
154
155
|
abandon(rootId: string, reason: string): Promise<RecoveryOutcome[]>;
|
|
@@ -37,7 +37,7 @@ export declare function claudeUsage(result: any): {
|
|
|
37
37
|
};
|
|
38
38
|
/**
|
|
39
39
|
* Whether a runtime's usage report (codexUsage or claudeUsage) lets it work again (ALPD §58):
|
|
40
|
-
* true when every window has room, false
|
|
40
|
+
* true when every window has room, false on explicit provider denial, a used-up window or spending cap, and
|
|
41
41
|
* undefined when the report says nothing either way.
|
|
42
42
|
*/
|
|
43
43
|
export declare function usageAllows(usage: any): boolean | undefined;
|
package/dist/runtime-context.js
CHANGED
|
@@ -46,7 +46,7 @@ function claudeUsage(result) {
|
|
|
46
46
|
function usageAllows(usage) {
|
|
47
47
|
if (!usage?.available) return void 0;
|
|
48
48
|
const limits = Array.isArray(usage.limits) ? usage.limits : [];
|
|
49
|
-
if (limits.some((limit) => limit?.spendControlReached === true)) return false;
|
|
49
|
+
if (usage.ordinaryUsageAllowed === false || limits.some((limit) => limit?.spendControlReached === true)) return false;
|
|
50
50
|
const windows = limits.length ? limits.flatMap((limit) => limit?.windows ?? []) : usage.windows ?? [];
|
|
51
51
|
const known = windows.filter((window) => typeof window?.usedPercent === "number");
|
|
52
52
|
if (!known.length) return void 0;
|