@messenger-agent/claude-agent 0.26.0-alpha.2 → 0.26.0-alpha.5
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/assets/workspace-templates/basic/AGENTS.md +14 -0
- package/dist/assets/workspace-templates/developer/AGENTS.md +14 -0
- package/dist/live-session.d.ts +5 -0
- package/dist/live-session.js +1 -1
- package/dist/pending-asks.d.ts +5 -0
- package/dist/pending-asks.js +9 -7
- package/dist/routes/chat.js +7 -7
- package/dist/schemas.d.ts +15 -0
- package/dist/schemas.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Working In This Workspace
|
|
2
|
+
|
|
3
|
+
Before making changes:
|
|
4
|
+
|
|
5
|
+
- Inspect the workspace structure and read the relevant README, project documentation, and any more specific `AGENTS.md` files.
|
|
6
|
+
- Follow the project's existing conventions, package manager, lockfiles, scripts, and test commands.
|
|
7
|
+
- Keep changes focused. Preserve unrelated user changes and do not overwrite files you have not understood.
|
|
8
|
+
- Run the most relevant available checks after editing and clearly report anything that could not be verified.
|
|
9
|
+
|
|
10
|
+
## Environment
|
|
11
|
+
|
|
12
|
+
This basic workspace is intended for source inspection, scripting, and lightweight development. Common tools include Bash, Git, Python 3, Node.js, ripgrep, curl, and GitHub/GitLab CLI tools.
|
|
13
|
+
|
|
14
|
+
System package installation and `sudo` access are not available. If the task requires a compiler, Rust, native system libraries, or other missing system dependencies, explain the limitation and recommend using a developer workspace.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Working In This Workspace
|
|
2
|
+
|
|
3
|
+
Before making changes:
|
|
4
|
+
|
|
5
|
+
- Inspect the workspace structure and read the relevant README, project documentation, and any more specific `AGENTS.md` files.
|
|
6
|
+
- Follow the project's existing conventions, package manager, lockfiles, scripts, and test commands.
|
|
7
|
+
- Keep changes focused. Preserve unrelated user changes and do not overwrite files you have not understood.
|
|
8
|
+
- Run the relevant tests, lint checks, or builds after editing and clearly report anything that could not be verified.
|
|
9
|
+
|
|
10
|
+
## Environment
|
|
11
|
+
|
|
12
|
+
This developer workspace includes common development tools, C/C++ build tools, Rust, ffmpeg, and `sudo`-based apt package installation.
|
|
13
|
+
|
|
14
|
+
Prefer the project's existing toolchain and package manager. Install additional system packages only when the task genuinely requires them, and avoid unrelated environment changes.
|
package/dist/live-session.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ManagedTaskExecutionContext } from "@messenger-agent/shared/managed-task-tools";
|
|
2
2
|
import { type Options, type PermissionMode, type SDKMessage } from "./claude.js";
|
|
3
|
+
import type { AgentEffort } from "./schemas.js";
|
|
3
4
|
type CanUseTool = NonNullable<Options["canUseTool"]>;
|
|
4
5
|
type PermissionHandler = (...args: Parameters<CanUseTool>) => ReturnType<CanUseTool>;
|
|
5
6
|
export type TurnMessageHandler = (message: SDKMessage) => Promise<boolean> | boolean;
|
|
@@ -13,6 +14,7 @@ export type TurnReservation = {
|
|
|
13
14
|
};
|
|
14
15
|
export type TurnSettings = {
|
|
15
16
|
model?: string;
|
|
17
|
+
effort: AgentEffort;
|
|
16
18
|
agentMode: "default" | "plan";
|
|
17
19
|
managedTaskContext: ManagedTaskExecutionContext;
|
|
18
20
|
};
|
|
@@ -20,6 +22,7 @@ export type LiveSessionInit = {
|
|
|
20
22
|
conversationId: string;
|
|
21
23
|
workdir: string;
|
|
22
24
|
model?: string;
|
|
25
|
+
effort: AgentEffort;
|
|
23
26
|
agentMode: "default" | "plan";
|
|
24
27
|
managedTaskContext: ManagedTaskExecutionContext;
|
|
25
28
|
llmProxyBinding?: string;
|
|
@@ -45,10 +48,12 @@ export declare class LiveSession {
|
|
|
45
48
|
private generation;
|
|
46
49
|
private _conversationId;
|
|
47
50
|
private _model?;
|
|
51
|
+
private _effort;
|
|
48
52
|
private _agentMode;
|
|
49
53
|
constructor(init: LiveSessionInit);
|
|
50
54
|
get conversationId(): string;
|
|
51
55
|
get model(): string | undefined;
|
|
56
|
+
get effort(): AgentEffort;
|
|
52
57
|
get agentMode(): "default" | "plan";
|
|
53
58
|
get isDead(): boolean;
|
|
54
59
|
get wasCancelled(): boolean;
|
package/dist/live-session.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as r}from"@messenger-agent/shared/logger";import{query as
|
|
1
|
+
import{logger as r}from"@messenger-agent/shared/logger";import{query as f}from"./claude.js";import{createInputQueue as m}from"./input-queue.js";import{claudeExecutionPermissionMode as T}from"./permission.js";function l(i,e){return{type:"user",parent_tool_use_id:null,message:{role:"user",content:i},origin:{kind:"human"},...e?{priority:e}:null}}function g(i){i.type==="stream_event"&&i.event.type==="content_block_delta"||i.type==="system"&&i.subtype==="thinking_tokens"||r.debug("Received chat stream event:",i)}class v{workdir;managedTaskContext;llmProxyBinding;inputQueue=m();abortController=new AbortController;sdkQuery;idleTimeoutMs;onRecycle;currentTurn;transition=Promise.resolve();idleTimer;pumpStarted=!1;dead=!1;cancelIntent=!1;generation=0;_conversationId;_model;_effort;_agentMode;constructor(e){this._conversationId=e.conversationId,this.workdir=e.workdir,this._model=e.model,this._effort=e.effort,this._agentMode=e.agentMode,this.managedTaskContext=e.managedTaskContext,this.llmProxyBinding=e.llmProxyBinding,this.idleTimeoutMs=e.idleTimeoutMs,this.onRecycle=e.onRecycle;const t=(...s)=>{const n=this.currentTurn;return!n||n.settled||this.cancelIntent?Promise.resolve({behavior:"deny",message:"Claude conversation is no longer active"}):n.permissionHandler(...s)};this.sdkQuery=f({prompt:this.inputQueue.iterable,options:e.buildOptions(this.abortController,t,this.managedTaskContext)}),this.resetIdleTimer()}get conversationId(){return this._conversationId}get model(){return this._model}get effort(){return this._effort}get agentMode(){return this._agentMode}get isDead(){return this.dead}get wasCancelled(){return this.cancelIntent}get currentGeneration(){return this.generation}hasActiveOwner(){return!!(this.currentTurn&&!this.currentTurn.settled)}bindConversation(e){this._conversationId=e}updateManagedTaskContext(e){for(const t of Object.keys(this.managedTaskContext))delete this.managedTaskContext[t];Object.assign(this.managedTaskContext,e)}reserveTurn(e,t,s,n){return this.withTransition(async()=>{if(this.dead||this.cancelIntent)throw new Error(`Claude session ${this.conversationId} is closed`);if(this.clearIdleTimer(),this.updateManagedTaskContext(n.managedTaskContext),this.hasActiveOwner())return this.inputQueue.push(l(e,"next")),{kind:"interjection",generation:this.generation};n.model!==this._model&&(await this.sdkQuery.setModel?.(n.model),this._model=n.model),n.effort!==this._effort&&(await this.sdkQuery.applyFlagSettings({effortLevel:n.effort}),this._effort=n.effort),n.agentMode!==this._agentMode&&(await this.sdkQuery.setPermissionMode?.(n.agentMode==="plan"?"plan":T()),this._agentMode=n.agentMode);const o=++this.generation;let a,d;const h=new Promise((u,c)=>{a=u,d=c});return this.currentTurn={generation:o,handler:t,permissionHandler:s,resolve:a,reject:d,settled:!1},this.pumpStarted||(this.pumpStarted=!0,this.pump()),this.inputQueue.push(l(e)),{kind:"owner",generation:o,done:h}})}async setModel(e){await this.withTransition(async()=>{e===this._model||this.dead||this.cancelIntent||(await this.sdkQuery.setModel?.(e),this._model=e)})}async setPermissionMode(e){await this.withTransition(async()=>{this.dead||this.cancelIntent||(await this.sdkQuery.setPermissionMode?.(e),this._agentMode=e==="plan"?"plan":"default")})}abort(){this.cancelIntent=!0,this.withTransition(async()=>{this.dead||(this.dead=!0,this.clearIdleTimer(),this.inputQueue.close(),this.abortController.abort())})}withTransition(e){const t=this.transition.then(e,e);return this.transition=t.then(()=>{},()=>{}),t}async pump(){try{for await(const t of this.sdkQuery){g(t);const s=this.currentTurn;if(!s||s.settled)continue;await s.handler(t)&&this.settleTurn(s,void 0)}this.dead=!0;const e=this.currentTurn;e&&!e.settled&&this.settleTurn(e,void 0)}catch(e){this.dead=!0;const t=this.currentTurn;t&&!t.settled?this.settleTurn(t,e):this.cancelIntent||r.error(`Claude session ${this.conversationId} pump failed:`,e)}finally{this.clearIdleTimer(),this.onRecycle(this,this.generation)}}settleTurn(e,t){e.settled||(e.settled=!0,this.currentTurn===e&&(this.currentTurn=void 0),!this.dead&&!this.cancelIntent&&this.resetIdleTimer(),t===void 0?e.resolve():e.reject(t))}resetIdleTimer(){this.clearIdleTimer(),!(this.dead||this.cancelIntent)&&(this.idleTimer=setTimeout(()=>{this.withTransition(async()=>{if(this.dead||this.cancelIntent||this.hasActiveOwner()){!this.dead&&!this.cancelIntent&&this.resetIdleTimer();return}r.info(`Recycling idle Claude session ${this.conversationId}`),this.dead=!0,this.inputQueue.close(),this.sdkQuery.close?.(),this.onRecycle(this,this.generation)})},this.idleTimeoutMs),this.idleTimer.unref?.())}clearIdleTimer(){this.idleTimer&&(clearTimeout(this.idleTimer),this.idleTimer=void 0)}}export{v as LiveSession};
|
package/dist/pending-asks.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentEffort } from "./schemas.js";
|
|
1
2
|
/** SDK tool names whose permission request is satisfied by a later client response. */
|
|
2
3
|
export declare const PENDING_ASK_TOOL_NAMES: readonly ["AskUserQuestion"];
|
|
3
4
|
export declare const PENDING_APPROVAL_TOOL_NAMES: readonly ["ExitPlanMode"];
|
|
@@ -11,6 +12,7 @@ export type PendingAskRecord = {
|
|
|
11
12
|
toolCallId: string;
|
|
12
13
|
workdir: string;
|
|
13
14
|
model?: string;
|
|
15
|
+
effort?: AgentEffort;
|
|
14
16
|
agentMode?: string;
|
|
15
17
|
toolName: PendingAskToolName;
|
|
16
18
|
input: unknown;
|
|
@@ -24,6 +26,7 @@ export type PendingApprovalRecord = {
|
|
|
24
26
|
toolCallId: string;
|
|
25
27
|
workdir: string;
|
|
26
28
|
model?: string;
|
|
29
|
+
effort?: AgentEffort;
|
|
27
30
|
agentMode?: string;
|
|
28
31
|
toolName: PendingApprovalToolName;
|
|
29
32
|
input: unknown;
|
|
@@ -49,6 +52,7 @@ export declare function savePendingAsk(params: {
|
|
|
49
52
|
toolCallId: string;
|
|
50
53
|
workdir: string;
|
|
51
54
|
model?: string;
|
|
55
|
+
effort?: AgentEffort;
|
|
52
56
|
agentMode?: string;
|
|
53
57
|
toolName: PendingAskToolName;
|
|
54
58
|
input: unknown;
|
|
@@ -60,6 +64,7 @@ export declare function savePendingApproval(params: {
|
|
|
60
64
|
toolCallId: string;
|
|
61
65
|
workdir: string;
|
|
62
66
|
model?: string;
|
|
67
|
+
effort?: AgentEffort;
|
|
63
68
|
agentMode?: string;
|
|
64
69
|
toolName: PendingApprovalToolName;
|
|
65
70
|
input: unknown;
|
package/dist/pending-asks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{randomUUID as s}from"node:crypto";import{mkdirSync as
|
|
1
|
+
import{randomUUID as s}from"node:crypto";import{mkdirSync as E}from"node:fs";import{dirname as v,join as k}from"node:path";import{DatabaseSync as A}from"node:sqlite";import{appConfig as m}from"./config.js";import{AgentEffortSchema as x}from"./schemas.js";const W=["AskUserQuestion"],b=["ExitPlanMode"],r=new Map,_=k(m.dataDir,"pending-asks.sqlite");E(v(_),{recursive:!0});const i=new A(_);i.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS pending_tools (
|
|
3
3
|
tool_call_id TEXT PRIMARY KEY,
|
|
4
4
|
id TEXT NOT NULL,
|
|
@@ -6,6 +6,7 @@ import{randomUUID as s}from"node:crypto";import{mkdirSync as v}from"node:fs";imp
|
|
|
6
6
|
conversation_id TEXT NOT NULL,
|
|
7
7
|
workdir TEXT NOT NULL,
|
|
8
8
|
model TEXT,
|
|
9
|
+
effort TEXT,
|
|
9
10
|
agent_mode TEXT,
|
|
10
11
|
tool_name TEXT NOT NULL,
|
|
11
12
|
input_json TEXT NOT NULL,
|
|
@@ -15,28 +16,29 @@ import{randomUUID as s}from"node:crypto";import{mkdirSync as v}from"node:fs";imp
|
|
|
15
16
|
);
|
|
16
17
|
CREATE INDEX IF NOT EXISTS idx_pending_tools_conversation_updated
|
|
17
18
|
ON pending_tools (conversation_id, updated_at);
|
|
18
|
-
`);const
|
|
19
|
+
`);const N=i.prepare("PRAGMA table_info(pending_tools)").all();N.some(e=>e.name==="effort")||i.exec("ALTER TABLE pending_tools ADD COLUMN effort TEXT");const P=i.prepare(`
|
|
19
20
|
INSERT INTO pending_tools (
|
|
20
|
-
tool_call_id, id, kind, conversation_id, workdir, model, agent_mode, tool_name, input_json, approval_json, created_at, updated_at
|
|
21
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
21
|
+
tool_call_id, id, kind, conversation_id, workdir, model, effort, agent_mode, tool_name, input_json, approval_json, created_at, updated_at
|
|
22
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
22
23
|
ON CONFLICT(tool_call_id) DO UPDATE SET
|
|
23
24
|
id = excluded.id,
|
|
24
25
|
kind = excluded.kind,
|
|
25
26
|
conversation_id = excluded.conversation_id,
|
|
26
27
|
workdir = excluded.workdir,
|
|
27
28
|
model = excluded.model,
|
|
29
|
+
effort = excluded.effort,
|
|
28
30
|
agent_mode = excluded.agent_mode,
|
|
29
31
|
tool_name = excluded.tool_name,
|
|
30
32
|
input_json = excluded.input_json,
|
|
31
33
|
approval_json = excluded.approval_json,
|
|
32
34
|
updated_at = excluded.updated_at
|
|
33
|
-
`),
|
|
35
|
+
`),O=i.prepare("SELECT * FROM pending_tools WHERE tool_call_id = ?"),I=i.prepare(`
|
|
34
36
|
SELECT * FROM pending_tools
|
|
35
37
|
WHERE conversation_id = ?
|
|
36
38
|
ORDER BY updated_at DESC, created_at DESC
|
|
37
39
|
LIMIT 1
|
|
38
|
-
`),
|
|
40
|
+
`),C=i.prepare(`
|
|
39
41
|
UPDATE pending_tools
|
|
40
42
|
SET conversation_id = ?, updated_at = ?
|
|
41
43
|
WHERE conversation_id = ?
|
|
42
|
-
`),l=i.prepare("DELETE FROM pending_tools WHERE tool_call_id = ?"),
|
|
44
|
+
`),l=i.prepare("DELETE FROM pending_tools WHERE tool_call_id = ?"),L=i.prepare("SELECT * FROM pending_tools ORDER BY updated_at DESC, created_at DESC");function u(e){let n,t;const o=new Promise((d,a)=>{n=d,t=a});return{record:e,resolve:n,reject:t,promise:o}}function c(e){try{const n=JSON.parse(e.input_json),t={id:e.id,conversationId:e.conversation_id,toolCallId:e.tool_call_id,workdir:e.workdir,model:e.model??void 0,effort:x.safeParse(e.effort).data,agentMode:e.agent_mode??void 0,input:n,createdAt:e.created_at,updatedAt:e.updated_at};if(e.kind==="approval"){const o=e.approval_json?JSON.parse(e.approval_json):{};return e.tool_name!=="ExitPlanMode"||typeof o.approveId!="string"?void 0:{...t,kind:"approval",toolName:"ExitPlanMode",approveId:o.approveId}}return e.kind!=="ask_user"||e.tool_name!=="AskUserQuestion"?void 0:{...t,kind:"ask_user",toolName:"AskUserQuestion"}}catch{return}}function g(e){P.run(e.toolCallId,e.id,e.kind,e.conversationId,e.workdir,e.model??null,e.effort??null,e.agentMode??null,e.toolName,JSON.stringify(e.input),e.kind==="approval"?JSON.stringify({approveId:e.approveId}):null,e.createdAt,e.updatedAt)}function T(e){const n=r.get(e.toolCallId);if(n)return n;const t=u(e);return r.set(e.toolCallId,t),t}function p(e){const n=r.get(e)?.record;if(n)return n;const t=O.get(e),o=t?c(t):void 0;if(o)return T(o),o}function f(e){const n=Array.from(r.values(),d=>d.record).filter(d=>d.conversationId===e).sort((d,a)=>a.updatedAt.localeCompare(d.updatedAt))[0];if(n)return n;const t=I.get(e),o=t?c(t):void 0;if(o)return T(o),o}function H(e){const n=r.get(e.toolCallId);if(n?.record.kind==="ask_user")return n.record;const t=new Date().toISOString(),o={id:s(),kind:"ask_user",conversationId:e.conversationId,toolCallId:e.toolCallId,workdir:e.workdir,model:e.model,effort:e.effort,agentMode:e.agentMode,toolName:e.toolName,input:e.input,createdAt:t,updatedAt:t};return r.set(e.toolCallId,u(o)),g(o),o}function S(e){const n=p(e);return n?.kind==="ask_user"?n:void 0}function h(e){const n=f(e);return n?.kind==="ask_user"?n:void 0}function G(e){const n=r.get(e.toolCallId);if(n?.record.kind==="approval")return n.record;const t=new Date().toISOString(),o={id:s(),kind:"approval",conversationId:e.conversationId,toolCallId:e.toolCallId,workdir:e.workdir,model:e.model,effort:e.effort,agentMode:e.agentMode,toolName:e.toolName,input:e.input,approveId:s(),createdAt:t,updatedAt:t};return r.set(e.toolCallId,u(o)),g(o),o}function D(e){const n=p(e);return n?.kind==="approval"?n:void 0}function J(e){const n=f(e);return n?.kind==="approval"?n:void 0}function Y(e){return p(e)}function Q(e){return f(e)}function K(e,n){w(e,n)}function w(e,n){const t=new Date().toISOString();let o=!1;for(const d of r.values())d.record.conversationId===e&&(d.record.conversationId=n,d.record.updatedAt=t,o=!0);o&&C.run(n,t,e)}function V(e){return r.get(e)?.promise}function q(e,n){const t=r.get(e)??(S(e)?r.get(e):void 0);return!t||t.record.kind!=="ask_user"?!1:(r.delete(e),l.run(e),t.resolve(n),!0)}function $(e){return r.get(e)?.promise}function z(e,n){const t=r.get(e)??(D(e)?r.get(e):void 0);return!t||t.record.kind!=="approval"?!1:(r.delete(e),l.run(e),t.resolve(n),!0)}function Z(e,n={}){M(e,n)}function M(e,n={}){const t=r.get(e);r.delete(e),l.run(e),t&&n.rejectWait&&t.reject(new Error(`Pending client tool was cancelled: ${e}`))}function ee(){return R().filter(e=>e.kind==="ask_user")}function R(){const e=new Map;for(const n of L.all()){const t=c(n);t&&e.set(t.toolCallId,t)}for(const n of r.values())e.set(n.record.toolCallId,n.record);return Array.from(e.values()).sort((n,t)=>t.updatedAt.localeCompare(n.updatedAt))}function ne(){r.clear(),i.close()}export{b as PENDING_APPROVAL_TOOL_NAMES,W as PENDING_ASK_TOOL_NAMES,z as answerPendingApproval,q as answerPendingAsk,ne as closePendingToolsDatabaseForTest,Z as deletePendingAsk,M as deletePendingClientTool,J as findPendingApprovalByConversation,h as findPendingAskByConversation,Q as findPendingClientToolByConversation,ee as listPendingAsks,R as listPendingClientTools,D as loadPendingApproval,S as loadPendingAsk,Y as loadPendingClientTool,G as savePendingApproval,H as savePendingAsk,K as updatePendingAskConversation,w as updatePendingClientToolConversation,$ as waitPendingApproval,V as waitPendingAsk};
|
package/dist/routes/chat.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{randomUUID as
|
|
2
|
-
`).trim();if(!r)throw new
|
|
1
|
+
import{randomUUID as $e}from"node:crypto";import{existsSync as ut,mkdirSync as ct}from"node:fs";import{Hono as pt}from"hono";import{HTTPException as ge}from"hono/http-exception";import{zValidator as ft}from"@hono/zod-validator";import{streamSSE as mt}from"hono/streaming";import{claudePlatformInstructions as wt}from"../platform-instructions.js";import{logger as B}from"@messenger-agent/shared/logger";import{appConfig as y}from"../config.js";import{resolveAgentWorkdir as yt,resolveAgentWorkspaceRoot as vt}from"@messenger-agent/shared/agent-workspaces";import{isManagedTaskToolName as Le}from"@messenger-agent/shared/managed-task-tools";import{saveUploadedFilePart as kt}from"@messenger-agent/shared/uploaded-files";import{answerPendingApproval as We,answerPendingAsk as Fe,deletePendingClientTool as He,findPendingClientToolByConversation as gt,listPendingClientTools as Xe,loadPendingClientTool as Tt,savePendingAsk as _t,savePendingApproval as It,updatePendingAskConversation as ht,waitPendingApproval as Ct,waitPendingAsk as xt}from"../pending-asks.js";import{AgentAnswerToolPartSchema as bt,ChatBodySchema as St}from"../schemas.js";import{createTaskAggregator as At}from"../task-aggregator.js";import{createManagedTaskMcpServer as Mt,MANAGED_TASK_MCP_SERVER_NAME as Qe}from"../managed-task-mcp.js";import{claudeExecutionPermissionMode as Et,claudePermissionOptions as Pt}from"../permission.js";import{claudeContextSnapshot as Dt,claudeTokenUsage as Ot}from"../token-usage.js";import{SessionManager as Rt}from"../session-manager.js";import{getLlmProxyBinding as Nt,moveLlmProxyBinding as jt,setLlmProxyBinding as Bt}from"../llm-proxy-bindings.js";const te=new pt,Q=new Rt(()=>y.claude.sessionIdleTimeoutMs??36e5),K=new Set;function Ut(e){if(Le(e))return!0;const n=`mcp__${Qe}__`;return e.startsWith(n)&&Le(e.slice(n.length))}function qt(e){if(!e||typeof e!="object"||Array.isArray(e))return;const n=e.structuredContent;return n&&typeof n=="object"&&!Array.isArray(n)?n:void 0}function $t(){const e=new Set(Xe().map(n=>n.conversationId));return{active:K.size,waiting:e.size}}class U extends Error{status;constructor(n,r){super(r),this.status=n,this.name="ChatRequestError"}}const A=new Map;function Ke(e){return e?.trim().toLowerCase()==="plan"?"plan":"default"}function Lt(e){return{type:"not_found_error",code:"conversation_not_found",message:`Conversation not found or already completed: ${e}`,param:"conversation_id"}}function _(e){return!!(e&&typeof e=="object")}function Wt(e){return e.type==="file"&&"mediaType"in e&&typeof e.mediaType=="string"&&"url"in e&&typeof e.url=="string"&&(!("filename"in e)||e.filename===void 0||typeof e.filename=="string")}async function Ft(e){if(e.type==="text"&&typeof e.text=="string")return e.text;if(Wt(e))return kt(e,y.fileUploads.tempDir);if(e.type!=="step-start")throw new ge(400,{message:`Unsupported message part type: ${e.type}`})}async function Ht(e){const r=(await Promise.all(e.map(Ft))).filter(l=>!!(l&&l.trim().length>0)).join(`
|
|
2
|
+
`).trim();if(!r)throw new ge(400,{message:"No supported message content found"});return r}function Xt(e){for(const n of e){const r=bt.safeParse(n);if(r.success)return r.data}}function Te(e){if(typeof e=="string")return e;if(_(e)){if(typeof e.answer=="string")return e.answer;if(typeof e.text=="string")return e.text;if(_(e.answers))return Object.values(e.answers).map(n=>String(n)).join(`
|
|
3
3
|
`);if(Array.isArray(e.answers))return e.answers.map(n=>{if(typeof n=="string")return n;if(_(n)){if(typeof n.answer=="string")return n.answer;if(typeof n.text=="string")return n.text}return JSON.stringify(n)}).join(`
|
|
4
|
-
`)}return JSON.stringify(e)}function
|
|
5
|
-
`)}return
|
|
6
|
-
`)}function Zt(e){return!!(e&&e.state==="output-available"&&(e.toolName==="AskUserQuestion"||e.toolName==="ask_user_question"))}function en(e){return!!(e&&e.state==="approval-responded")}async function tn(e,n){return e?e.state==="approval-responded"?e.approval.reason??"":Qe(e.output):Wt(n)}function nn(e,n){return mt(y,e,n)}function on(e){return e==="AskUserQuestion"}function rn(e){return e==="ExitPlanMode"}function an(e){const n="subagent_type"in e?e.subagent_type:void 0,r="parent_tool_use_id"in e?e.parent_tool_use_id:void 0;return!!n||!!r}function sn(e){return"session_id"in e?e.session_id:void 0}function ln(e){return e.subtype==="success"&&e.origin?.kind==="task-notification"&&e.num_turns===0&&e.result===""&&e.usage.input_tokens===0&&e.usage.output_tokens===0&&e.usage.cache_creation_input_tokens===0&&e.usage.cache_read_input_tokens===0&&Object.keys(e.modelUsage).length===0}function C(e,n){return e?.get(n)??void 0}function dn(e){const n=C(e,"X-Matrix-Room-Id")?.trim(),r=C(e,"X-Matrix-Thread-ID")?.trim();return n&&r?`${n}/${r}`:void 0}function un(e){const n=C(e,"X-Matrix-Room-Id")?.trim(),r=C(e,"X-Matrix-Event-ID")?.trim(),s=C(e,"X-Matrix-Thread-ID")?.trim();if(!(!n||!r))return{roomId:n,eventId:r,...s?{threadRootEventId:s}:null}}ee.post("/v1/chat/:conversation_id/cancel",e=>{const n=e.req.param("conversation_id");return cn(n)?e.json({success:!0}):e.json({error:$t(n)},404)});function cn(e){return X.cancel(e)}ee.get("/admin/status",e=>{const n=Fe().map(s=>({conversationId:s.conversationId,toolCallId:s.toolCallId,toolName:s.toolName,kind:s.kind,approveId:s.kind==="approval"?s.approveId:void 0,since:s.createdAt,agentMode:s.agentMode,model:s.model})),r=Ut();return e.json({activeTaskCount:r.active,waitingClientToolCount:n.length,clientToolWaits:n})});async function ze({body:e,headers:n}){const r=C(n,"X-Matrix-Workdir"),s=C(n,"X-Matrix-Workspace-ID"),x=dn(n),Ge=un(n);let U,_e;try{U=nn(s,r),_e=wt(y,s)}catch(I){throw new B(400,I instanceof Error?I.message:"Invalid workspace")}if(r&&!lt(U))throw new B(400,`Workdir not found: ${U}`);if(dt(U,{recursive:!0}),e.fork&&!("sessionId"in e.fork))throw new B(400,"Claude fork requires sessionId and messageId");const K=e.fork&&"sessionId"in e.fork?e.fork:void 0,f=Ft(e.message.parts),l=f&&(Zt(f)||en(f))?kt(f.toolCallId):e.conversationId?vt(e.conversationId):void 0,m=l?A.get(l.conversationId):void 0,b=await tn(f,e.message.parts),g=f?void 0:l,$=l&&!m?l.conversationId:e.conversationId,te=C(n,"X-Elevo-LLM-Binding")?.trim()||void 0;let M=K?void 0:X.get($);const ne=M?.llmProxyBinding??Nt($);if(te&&ne&&te!==ne)throw new B(409,"LLM proxy binding does not match the existing conversation");const P=ne??te;if(M&&P&&!M.llmProxyBinding){if(M.hasActiveOwner())throw new B(409,"Cannot attach an LLM proxy binding while the conversation is active");M.abort(),M=void 0}const Ie=e.model||y.claude.defaultModel,J=l&&!m?l.workdir:U,q=l?.kind==="approval"&&Te(l,f,b).approved?"default":l?.agentMode?Xe(l.agentMode):Xe(C(n,"X-Matrix-Agent-Mode")),L=l&&!m?l.model??Ie:Ie;return{run:async(I,W)=>{if(l&&m&&!g){const t={};Q.add(t);let a=!1,i;const o=async()=>{a||(a=!0,i&&(clearTimeout(i),i=void 0),await I.writeDone())},p=async c=>{i&&clearTimeout(i),await I.writeData(c),a||(i=setTimeout(()=>{I.writeData({type:"heartbeat"}).catch(()=>{})},6e4))},u=async c=>{a||await p(c)};try{if(await m.attach({writeData:u,writeDone:o}),l.kind==="ask_user")Le(l.toolCallId,Jt(l.input,f,b));else{const c=Te(l,f,b);c.approved&&await X.get(l.conversationId)?.setPermissionMode(At()),qe(l.toolCallId,c)}await m.done}catch(c){j.error("Claude live ask continuation failed:",c),await u({type:"error",errorText:c instanceof Error?c.message:String(c)}),await o()}finally{i&&clearTimeout(i),Q.delete(t)}return}const he={};Q.add(he);const z=$??Ue();let w=z,Ce=!1,xe=!1,oe=!1,D=new Set,N=new Set;const re=new Map,ae=new Map,ie=new Map;let se=!1,le=!1,de,ue="stop",ce,pe,O,be=new Set,Se=!1,T;const E=bt();let G=!1,Ve=0,R=!1;const fe=new Set;let v=!1,V,me=!1,S,F;const Ye=new Promise(t=>{F=t});let Ae;const Ze=new Promise(t=>{Ae=t}),Me=()=>{T=setTimeout(()=>{d({type:"heartbeat"}).catch(()=>{})},6e4)},et=async t=>{T&&clearTimeout(T),await I.writeData(t),v||Me()};V={writeData:async t=>{v||await et(t)},writeDone:async()=>{v||(v=!0,T&&(clearTimeout(T),T=void 0),await I.writeDone())}};const d=async t=>{v||await V.writeData(t)},Ee=async()=>{v||(await V.writeDone(),v=!0)},tt=async()=>{O||(O={activityId:Ue()},await d({type:"data",kind:"compact",data:{phase:"start",activityId:O.activityId}}))},we=async(t,a={})=>{if(!O)return;const i=O;O=void 0,await d({type:"data",kind:"compact",data:{phase:"end",activityId:i.activityId,status:t,...a}})},H=async t=>{if(!(oe||v)){oe=!0;for(const a of D)await d({type:"text-end",id:a});D=new Set;for(const a of N)await d({type:"reasoning-end",id:a});N=new Set,xe&&(t==="stop"&&ce&&await d({type:"data",kind:"token_usage",data:ce}),await d({type:"finish-step"})),await d({type:"finish",finishReason:t}),await Ee()}},nt=async()=>{for(const t of D)await d({type:"text-end",id:t});D=new Set},ot=async()=>{for(const t of N)await d({type:"reasoning-end",id:t});N=new Set},Y=async()=>{await nt(),await ot()},h=async()=>{if(!G)return;G=!1,E.clearDirty(),await Y();const t=`todo-${z}-${Ve++}`;await d({type:"tool-input-available",toolCallId:t,toolName:"TodoWrite",input:E.snapshot()}),await d({type:"tool-output-available",toolCallId:t,output:"Task updated"})},Pe=async(t,a,i,o)=>{fe.has(t)||(fe.add(t),R=!0,W?.removeEventListener("abort",Z),o&&await d({type:"tool-approval-request",toolCallId:t,approveId:o.approveId}),await Ee(),S=setTimeout(()=>{j.warn(`Claude ${a} timed out after ${y.claude.askTimeoutMs}ms`,{conversationId:w,toolCallId:t}),A.delete(w),k.abort(),F()},y.claude.askTimeoutMs),S.unref?.(),Ae())},De=async t=>{D.has(t)||(D.add(t),await d({type:"text-start",id:t}))},Ne=async t=>{N.has(t)||(N.add(t),await d({type:"reasoning-start",id:t}))},rt=t=>{if(t===w)return;const a=w;w=t,X.bind(k,t),Ot(a,t,P),_t(a,t);const i=A.get(a);i&&(A.delete(a),A.set(t,i))},Oe=async t=>{Ce||(Ce=!0,rt(t),me||(me=!0,A.set(t,{attach:async a=>{S&&(clearTimeout(S),S=void 0),V=a,v=!1,R=!1},done:Ye,dispose:()=>{S&&(clearTimeout(S),S=void 0)}})),await d({type:"start",messageMetadata:{conversationId:t,threadId:t}}),await d({type:"start-step"}),xe=!0)},Re=()=>{me&&(A.get(w)?.dispose(),A.delete(w));for(const t of fe)We(t,{rejectWait:!0})},at=async()=>(await H(ue),Re(),F(),!0);Me();const it=async(t,a,i)=>{const{toolUseID:o}=i;if(on(t)){gt({conversationId:w,toolCallId:o,workdir:J,model:L,agentMode:q,toolName:"AskUserQuestion",input:a}),await Pe(o,"AskUserQuestion",a);const p=await ht(o);return p?"interrupted"in p?{behavior:"deny",message:"Question interrupted by text response",interrupt:!0,toolUseID:o}:{behavior:"allow",updatedInput:{...a,questions:Ke(a),answers:p.answers},toolUseID:o}:{behavior:"deny",message:`${t} requires user input; session will resume after user responds.`,toolUseID:o}}if(rn(t)){const p=Tt({conversationId:w,toolCallId:o,workdir:J,model:L,agentMode:q,toolName:"ExitPlanMode",input:a});await Pe(o,"ExitPlanMode",a,p);const u=await It(o);return u&&"interrupted"in u?{behavior:"deny",message:"Approval interrupted by text response",interrupt:!0,toolUseID:o,decisionClassification:"user_reject"}:u?.approved?{behavior:"allow",updatedInput:{...a,approval:u},toolUseID:o}:{behavior:"deny",message:u?.reason||"Denied by user",toolUseID:o,decisionClassification:"user_reject"}}return{behavior:"allow",toolUseID:o}},st=async t=>{if(an(t))return!1;const a=sn(t);if(a&&(await Oe(a),E.setSessionId(a)),R)return!1;switch(t.type){case"system":return t.subtype==="background_tasks_changed"?be=new Set(t.tasks.map(i=>i.task_id)):t.subtype==="status"?(t.status==="compacting"&&await tt(),t.compact_result==="success"?await we("completed"):t.compact_result==="failed"&&await we("failed",{error:t.compact_error})):t.subtype==="compact_boundary"&&await we("completed",{trigger:t.compact_metadata.trigger,preTokens:t.compact_metadata.pre_tokens,postTokens:t.compact_metadata.post_tokens,durationMs:t.compact_metadata.duration_ms}),!1;case"stream_event":{const i=t.event;switch(i.type){case"message_start":{de=i.message.id,se=!1,le=!1;break}case"content_block_start":{const o=`${de??t.session_id}:${i.index}`;i.content_block.type==="text"?(await h(),re.set(o,t.uuid),await De(t.uuid)):i.content_block.type==="thinking"&&(await h(),ae.set(o,t.uuid),await Ne(t.uuid));break}case"content_block_delta":{const o=i.delta,p=`${de??t.session_id}:${i.index}`;if(o.type==="text_delta"){await h(),se=!0;const u=re.get(p);if(!u){j.warn("Ignoring Claude text delta without content_block_start",{conversationId:w,blockKey:p});break}await d({type:"text-delta",id:u,delta:o.text})}else if(o.type==="thinking_delta"){await h(),le=!0;const u=ae.get(p);if(!u){j.warn("Ignoring Claude reasoning delta without content_block_start",{conversationId:w,blockKey:p});break}await d({type:"reasoning-delta",id:u,delta:o.thinking})}break}case"content_block_stop":break}return!1}case"assistant":{pe=Et(t.message)??pe,t.session_id&&t.uuid&&await d({type:"data",kind:"agent_session",data:{agentType:"claude",sessionId:t.session_id,messageId:t.uuid}});const i=t.message.content;if(typeof i=="string")break;for(const o of i)switch(o.type){case"thinking":{if(le||!o.thinking)break;await h(),await Ne(t.uuid),await d({type:"reasoning-delta",id:t.uuid,delta:o.thinking});break}case"text":{if(se||!o.text)break;await h(),await De(t.uuid),await d({type:"text-delta",id:t.uuid,delta:o.text});break}case"tool_use":{if(await Y(),ie.set(o.id,o.name),E.isTaskTool(o.name)){E.applyToolUse(o.id,o.name,o.input)&&(G=!0);break}await h(),await Y(),await d({type:"tool-input-available",toolCallId:o.id,toolName:o.name,input:o.input});break}}return await Y(),re.clear(),ae.clear(),!1}case"user":{const i=t.message.content;if(typeof i=="string")break;const o=i.filter(u=>u.type==="tool_result"),p=o.length===1?Bt(t.tool_use_result):void 0;for(const u of o){const c=u.tool_use_id,ve=u.content;if(E.isTaskToolCall(c)){E.applyToolResult(c,ve)&&(G=!0);continue}if(await h(),u.is_error===!0)await d({type:"tool-output-error",toolCallId:c,errorText:Ht(ve)});else{const Be=ie.get(c);await d({type:"tool-output-available",toolCallId:c,output:Be&&jt(Be)&&p!==void 0?p:ve})}ie.delete(c)}return!1}case"result":{if(be.size>0)return t.origin?.kind!=="task-notification"&&(Se=!0),!1;if(ln(t)&&!Se)return!1;ue=t.subtype==="success"||k.wasCancelled?"stop":"error";const i=Pt(t,pe);return ce=ue==="stop"?i:void 0,await h(),t.subtype!=="success"&&!k.wasCancelled&&await d({type:"error",errorText:t.errors?.filter(o=>o.trim()).join(`
|
|
7
|
-
`)||`Claude Code failed: ${t.subtype}`}),
|
|
8
|
-
`)}:null,CLAUDE_AGENT_SDK_CLIENT_APP:"coding-agent/claude-agent"}})});
|
|
4
|
+
`)}return JSON.stringify(e)}function Je(e){if(_(e)&&_(e.answers)){const n=Object.entries(e.answers).map(([r,l])=>`- ${r}:${String(l)}`);if(n.length>0)return["User answered previous question:",...n].join(`
|
|
5
|
+
`)}return Te(e)}function Qt(e){return typeof e=="string"?e:JSON.stringify(e)}function Kt(e,n){return _(e)&&typeof e.question=="string"?e.question:`Question ${n+1}`}function ze(e){return _(e)&&Array.isArray(e.questions)?e.questions:[]}function Jt(e,n){const r=ze(e);return _(n)&&_(n.answers)?Object.fromEntries(Object.entries(n.answers).map(([l,x])=>[l,String(x)])):r.length>0?Object.fromEntries(r.map((l,x)=>[Kt(l,x),Te(n)])):{answer:Te(n)}}function zt(e,n,r){return n&&n.state==="output-available"?n.output:{answers:r}}function Gt(e,n,r){return n&&n.state==="output-available"?{answers:Jt(e,n.output),output:n.output}:{answers:r}}function Vt(e,n){return!e||e.state!=="output-available"?`User answered previous question: ${n}`:Je(e.output)}function Yt(e){return _(e)&&typeof e.plan=="string"?e.plan:JSON.stringify(e)}function Zt(e){return{approved:!1,reason:e.trim()||void 0}}function Ge(e,n,r){return n&&n.state==="approval-responded"?n.approval:{id:e.approveId,...Zt(r)}}function _e(e,n,r){const l=Ge(e,n,r);if(l.id!==e.approveId)throw new ge(400,{message:"Tool approval id does not match pending approval"});return{approved:l.approved,reason:l.reason}}function en(e,n,r){const l=_e(e,n,r),x=[l.approved?`User approved tool ${e.toolName} plan:`:`User rejected tool ${e.toolName} plan:`,Yt(e.input)];return l.reason&&x.push(`Reason: ${l.reason}`),x.join(`
|
|
6
|
+
`)}function tn(e){return!!(e&&e.state==="output-available"&&(e.toolName==="AskUserQuestion"||e.toolName==="ask_user_question"))}function nn(e){return!!(e&&e.state==="approval-responded")}async function on(e,n){return e?e.state==="approval-responded"?e.approval.reason??"":Je(e.output):Ht(n)}function rn(e,n){return yt(y,e,n)}function an(e){return e==="AskUserQuestion"}function sn(e){return e==="ExitPlanMode"}function ln(e){return e==="Agent"||e==="Task"}function dn(e){const n="subagent_type"in e?e.subagent_type:void 0,r="parent_tool_use_id"in e?e.parent_tool_use_id:void 0;return!!n||!!r}function un(e){return"session_id"in e?e.session_id:void 0}function cn(e){return e.subtype==="success"&&e.origin?.kind==="task-notification"&&e.num_turns===0&&e.result===""&&e.usage.input_tokens===0&&e.usage.output_tokens===0&&e.usage.cache_creation_input_tokens===0&&e.usage.cache_read_input_tokens===0&&Object.keys(e.modelUsage).length===0}function C(e,n){return e?.get(n)??void 0}function pn(e){const n=C(e,"X-Matrix-Room-Id")?.trim(),r=C(e,"X-Matrix-Thread-ID")?.trim();return n&&r?`${n}/${r}`:void 0}function fn(e){const n=C(e,"X-Matrix-Room-Id")?.trim(),r=C(e,"X-Matrix-Event-ID")?.trim(),l=C(e,"X-Matrix-Thread-ID")?.trim();if(!(!n||!r))return{roomId:n,eventId:r,...l?{threadRootEventId:l}:null}}te.post("/v1/chat/:conversation_id/cancel",e=>{const n=e.req.param("conversation_id");return mn(n)?e.json({success:!0}):e.json({error:Lt(n)},404)});function mn(e){return Q.cancel(e)}te.get("/admin/status",e=>{const n=Xe().map(l=>({conversationId:l.conversationId,toolCallId:l.toolCallId,toolName:l.toolName,kind:l.kind,approveId:l.kind==="approval"?l.approveId:void 0,since:l.createdAt,agentMode:l.agentMode,model:l.model})),r=$t();return e.json({activeTaskCount:r.active,waitingClientToolCount:n.length,clientToolWaits:n})});async function Ve({body:e,headers:n}){const r=C(n,"X-Matrix-Workdir"),l=C(n,"X-Matrix-Workspace-ID"),x=pn(n),Ye=fn(n);let q,Ie;try{q=rn(l,r),Ie=vt(y,l)}catch(I){throw new U(400,I instanceof Error?I.message:"Invalid workspace")}if(r&&!ut(q))throw new U(400,`Workdir not found: ${q}`);if(ct(q,{recursive:!0}),e.fork&&!("sessionId"in e.fork))throw new U(400,"Claude fork requires sessionId and messageId");const J=e.fork&&"sessionId"in e.fork?e.fork:void 0,f=Xt(e.message.parts),i=f&&(tn(f)||nn(f))?Tt(f.toolCallId):e.conversationId?gt(e.conversationId):void 0,m=i?A.get(i.conversationId):void 0,b=await on(f,e.message.parts),g=f?void 0:i,$=i&&!m?i.conversationId:e.conversationId,ne=C(n,"X-Elevo-LLM-Binding")?.trim()||void 0;let M=J?void 0:Q.get($);const oe=M?.llmProxyBinding??Nt($);if(ne&&oe&&ne!==oe)throw new U(409,"LLM proxy binding does not match the existing conversation");const P=oe??ne;if(M&&P&&!M.llmProxyBinding){if(M.hasActiveOwner())throw new U(409,"Cannot attach an LLM proxy binding while the conversation is active");M.abort(),M=void 0}const he=e.model||y.claude.defaultModel,Ce=e.effort,z=i&&!m?i.workdir:q,L=i?.kind==="approval"&&_e(i,f,b).approved?"default":i?.agentMode?Ke(i.agentMode):Ke(C(n,"X-Matrix-Agent-Mode")),D=i&&!m?i.model??he:he,W=i&&!m?i.effort??Ce:Ce;return{run:async(I,F)=>{if(i&&m&&!g){const t={};K.add(t);let a=!1,s;const o=async()=>{a||(a=!0,s&&(clearTimeout(s),s=void 0),await I.writeDone())},p=async c=>{s&&clearTimeout(s),await I.writeData(c),a||(s=setTimeout(()=>{I.writeData({type:"heartbeat"}).catch(()=>{})},6e4))},u=async c=>{a||await p(c)};try{if(await m.attach({writeData:u,writeDone:o}),i.kind==="ask_user")Fe(i.toolCallId,Gt(i.input,f,b));else{const c=_e(i,f,b);c.approved&&await Q.get(i.conversationId)?.setPermissionMode(Et()),We(i.toolCallId,c)}await m.done}catch(c){B.error("Claude live ask continuation failed:",c),await u({type:"error",errorText:c instanceof Error?c.message:String(c)}),await o()}finally{s&&clearTimeout(s),K.delete(t)}return}const xe={};K.add(xe);const G=$??$e();let w=G,be=!1,Se=!1,re=!1,O=new Set,R=new Set;const ae=new Map,ie=new Map,se=new Map;let le=!1,de=!1,ue,ce="stop",pe,fe,N,Ae=new Set,Me=!1,T;const E=At();let V=!1,Ze=0,j=!1;const me=new Set;let v=!1,Y,we=!1,S,H;const et=new Promise(t=>{H=t});let Ee;const tt=new Promise(t=>{Ee=t}),Pe=()=>{T=setTimeout(()=>{d({type:"heartbeat"}).catch(()=>{})},6e4)},nt=async t=>{T&&clearTimeout(T),await I.writeData(t),v||Pe()};Y={writeData:async t=>{v||await nt(t)},writeDone:async()=>{v||(v=!0,T&&(clearTimeout(T),T=void 0),await I.writeDone())}};const d=async t=>{v||await Y.writeData(t)},De=async()=>{v||(await Y.writeDone(),v=!0)},ot=async()=>{N||(N={activityId:$e()},await d({type:"data",kind:"compact",data:{phase:"start",activityId:N.activityId}}))},ye=async(t,a={})=>{if(!N)return;const s=N;N=void 0,await d({type:"data",kind:"compact",data:{phase:"end",activityId:s.activityId,status:t,...a}})},X=async t=>{if(!(re||v)){re=!0;for(const a of O)await d({type:"text-end",id:a});O=new Set;for(const a of R)await d({type:"reasoning-end",id:a});R=new Set,Se&&(t==="stop"&&pe&&await d({type:"data",kind:"token_usage",data:pe}),await d({type:"finish-step"})),await d({type:"finish",finishReason:t}),await De()}},rt=async()=>{for(const t of O)await d({type:"text-end",id:t});O=new Set},at=async()=>{for(const t of R)await d({type:"reasoning-end",id:t});R=new Set},Z=async()=>{await rt(),await at()},h=async()=>{if(!V)return;V=!1,E.clearDirty(),await Z();const t=`todo-${G}-${Ze++}`;await d({type:"tool-input-available",toolCallId:t,toolName:"TodoWrite",input:E.snapshot()}),await d({type:"tool-output-available",toolCallId:t,output:"Task updated"})},Oe=async(t,a,s,o)=>{me.has(t)||(me.add(t),j=!0,F?.removeEventListener("abort",ee),o&&await d({type:"tool-approval-request",toolCallId:t,approveId:o.approveId}),await De(),S=setTimeout(()=>{B.warn(`Claude ${a} timed out after ${y.claude.askTimeoutMs}ms`,{conversationId:w,toolCallId:t}),A.delete(w),k.abort(),H()},y.claude.askTimeoutMs),S.unref?.(),Ee())},Re=async t=>{O.has(t)||(O.add(t),await d({type:"text-start",id:t}))},Ne=async t=>{R.has(t)||(R.add(t),await d({type:"reasoning-start",id:t}))},it=t=>{if(t===w)return;const a=w;w=t,Q.bind(k,t),jt(a,t,P),ht(a,t);const s=A.get(a);s&&(A.delete(a),A.set(t,s))},je=async t=>{be||(be=!0,it(t),we||(we=!0,A.set(t,{attach:async a=>{S&&(clearTimeout(S),S=void 0),Y=a,v=!1,j=!1},done:et,dispose:()=>{S&&(clearTimeout(S),S=void 0)}})),await d({type:"start",messageMetadata:{conversationId:t,threadId:t}}),await d({type:"start-step"}),Se=!0)},Be=()=>{we&&(A.get(w)?.dispose(),A.delete(w));for(const t of me)He(t,{rejectWait:!0})},st=async()=>(await X(ce),Be(),H(),!0);Pe();const lt=async(t,a,s)=>{const{toolUseID:o}=s;if(an(t)){_t({conversationId:w,toolCallId:o,workdir:z,model:D,effort:W,agentMode:L,toolName:"AskUserQuestion",input:a}),await Oe(o,"AskUserQuestion",a);const p=await xt(o);return p?"interrupted"in p?{behavior:"deny",message:"Question interrupted by text response",interrupt:!0,toolUseID:o}:{behavior:"allow",updatedInput:{...a,questions:ze(a),answers:p.answers},toolUseID:o}:{behavior:"deny",message:`${t} requires user input; session will resume after user responds.`,toolUseID:o}}if(sn(t)){const p=It({conversationId:w,toolCallId:o,workdir:z,model:D,effort:W,agentMode:L,toolName:"ExitPlanMode",input:a});await Oe(o,"ExitPlanMode",a,p);const u=await Ct(o);return u&&"interrupted"in u?{behavior:"deny",message:"Approval interrupted by text response",interrupt:!0,toolUseID:o,decisionClassification:"user_reject"}:u?.approved?{behavior:"allow",updatedInput:{...a,approval:u},toolUseID:o}:{behavior:"deny",message:u?.reason||"Denied by user",toolUseID:o,decisionClassification:"user_reject"}}return ln(t)?{behavior:"allow",updatedInput:{...a,model:D},toolUseID:o}:{behavior:"allow",toolUseID:o}},dt=async t=>{if(dn(t))return!1;const a=un(t);if(a&&(await je(a),E.setSessionId(a)),j)return!1;switch(t.type){case"system":return t.subtype==="background_tasks_changed"?Ae=new Set(t.tasks.map(s=>s.task_id)):t.subtype==="status"?(t.status==="compacting"&&await ot(),t.compact_result==="success"?await ye("completed"):t.compact_result==="failed"&&await ye("failed",{error:t.compact_error})):t.subtype==="compact_boundary"&&await ye("completed",{trigger:t.compact_metadata.trigger,preTokens:t.compact_metadata.pre_tokens,postTokens:t.compact_metadata.post_tokens,durationMs:t.compact_metadata.duration_ms}),!1;case"stream_event":{const s=t.event;switch(s.type){case"message_start":{ue=s.message.id,le=!1,de=!1;break}case"content_block_start":{const o=`${ue??t.session_id}:${s.index}`;s.content_block.type==="text"?(await h(),ae.set(o,t.uuid),await Re(t.uuid)):s.content_block.type==="thinking"&&(await h(),ie.set(o,t.uuid),await Ne(t.uuid));break}case"content_block_delta":{const o=s.delta,p=`${ue??t.session_id}:${s.index}`;if(o.type==="text_delta"){await h(),le=!0;const u=ae.get(p);if(!u){B.warn("Ignoring Claude text delta without content_block_start",{conversationId:w,blockKey:p});break}await d({type:"text-delta",id:u,delta:o.text})}else if(o.type==="thinking_delta"){await h(),de=!0;const u=ie.get(p);if(!u){B.warn("Ignoring Claude reasoning delta without content_block_start",{conversationId:w,blockKey:p});break}await d({type:"reasoning-delta",id:u,delta:o.thinking})}break}case"content_block_stop":break}return!1}case"assistant":{fe=Dt(t.message)??fe,t.session_id&&t.uuid&&await d({type:"data",kind:"agent_session",data:{agentType:"claude",sessionId:t.session_id,messageId:t.uuid}});const s=t.message.content;if(typeof s=="string")break;for(const o of s)switch(o.type){case"thinking":{if(de||!o.thinking)break;await h(),await Ne(t.uuid),await d({type:"reasoning-delta",id:t.uuid,delta:o.thinking});break}case"text":{if(le||!o.text)break;await h(),await Re(t.uuid),await d({type:"text-delta",id:t.uuid,delta:o.text});break}case"tool_use":{if(await Z(),se.set(o.id,o.name),E.isTaskTool(o.name)){E.applyToolUse(o.id,o.name,o.input)&&(V=!0);break}await h(),await Z(),await d({type:"tool-input-available",toolCallId:o.id,toolName:o.name,input:o.input});break}}return await Z(),ae.clear(),ie.clear(),!1}case"user":{const s=t.message.content;if(typeof s=="string")break;const o=s.filter(u=>u.type==="tool_result"),p=o.length===1?qt(t.tool_use_result):void 0;for(const u of o){const c=u.tool_use_id,ke=u.content;if(E.isTaskToolCall(c)){E.applyToolResult(c,ke)&&(V=!0);continue}if(await h(),u.is_error===!0)await d({type:"tool-output-error",toolCallId:c,errorText:Qt(ke)});else{const qe=se.get(c);await d({type:"tool-output-available",toolCallId:c,output:qe&&Ut(qe)&&p!==void 0?p:ke})}se.delete(c)}return!1}case"result":{if(Ae.size>0)return t.origin?.kind!=="task-notification"&&(Me=!0),!1;if(cn(t)&&!Me)return!1;ce=t.subtype==="success"||k.wasCancelled?"stop":"error";const s=Ot(t,fe);return pe=ce==="stop"?s:void 0,await h(),t.subtype!=="success"&&!k.wasCancelled&&await d({type:"error",errorText:t.errors?.filter(o=>o.trim()).join(`
|
|
7
|
+
`)||`Claude Code failed: ${t.subtype}`}),st()}}return!1},ve={threadRef:x,matrixEvent:Ye},k=M??Q.create({conversationId:G,workdir:z,model:D,effort:W,agentMode:L,managedTaskContext:ve,llmProxyBinding:P,buildOptions:(t,a,s)=>({abortController:t,cwd:z,includePartialMessages:!0,model:D,effort:W,maxTurns:y.claude.maxTurns,systemPrompt:{type:"preset",preset:"claude_code",append:wt},...Pt(L),tools:{type:"preset",preset:"claude_code"},mcpServers:{[Qe]:Mt({workspaceRoot:Ie,context:s})},disallowedTools:["EnterWorktree","ExitWorktree"],...J?{resume:J.sessionId,resumeSessionAt:J.messageId,forkSession:!0}:$?{resume:$}:null,canUseTool:a,env:{...process.env,...y.claude.apiKey?{ANTHROPIC_API_KEY:y.claude.apiKey}:null,...y.claude.baseUrl?{ANTHROPIC_BASE_URL:y.claude.baseUrl}:null,...P?{ANTHROPIC_CUSTOM_HEADERS:[process.env.ANTHROPIC_CUSTOM_HEADERS,`X-Elevo-LLM-Binding: ${P}`].filter(Boolean).join(`
|
|
8
|
+
`)}:null,CLAUDE_AGENT_SDK_CLIENT_APP:"coding-agent/claude-agent"}})});Bt(G,P),k.updateManagedTaskContext(ve);const ee=()=>k.abort();let Ue=!1;try{g&&m&&(await m.attach({writeData:async()=>{},writeDone:async()=>{}}),g.kind==="ask_user"?Fe(g.toolCallId,{interrupted:!0}):We(g.toolCallId,{interrupted:!0}),await m.done),i&&(!m||g)&&(i.kind==="ask_user"?await d(g?{type:"tool-output-error",toolCallId:i.toolCallId,toolName:i.toolName,errorText:"Question interrupted by text response"}:{type:"tool-output-available",toolCallId:i.toolCallId,output:zt(i,f,b)}):await d(g?{type:"tool-output-error",toolCallId:i.toolCallId,toolName:i.toolName,errorText:"Approval interrupted by text response"}:{type:"tool-output-available",toolCallId:i.toolCallId,output:Ge(i,f,b)}),(!g||!m)&&He(i.toolCallId));const t=i&&!m&&!g?i.kind==="ask_user"?Vt(f,b):en(i,f,b):b,a=await k.reserveTurn(t,dt,lt,{model:D,effort:W,agentMode:L,managedTaskContext:ve});if(a.kind==="interjection"){T&&clearTimeout(T),await I.writeDone();return}Ue=!0,F?.aborted&&ee(),F?.addEventListener("abort",ee,{once:!0}),await Promise.race([a.done,tt]),!j&&!re&&!v&&await X(k.wasCancelled||!k.isDead?"stop":"error")}catch(t){v?(B.error("Claude stream failed after downstream closed:",t),H()):(await je(w),F?.aborted||k.wasCancelled?await X("stop"):k.isDead?await X("error"):(B.error("Claude stream failed:",t),await d({type:"error",errorText:t instanceof Error?t.message:String(t)}),await X("error")))}finally{Ue&&F?.removeEventListener("abort",ee),T&&clearTimeout(T),K.delete(xe),j||Be(),j||H()}}}}async function jn(e,n){await(await Ve(e)).run(n,e.signal)}te.post("/v1/chat/stream",ft("json",St),async e=>{let n;try{n=await Ve({body:e.req.valid("json"),headers:e.req.raw.headers})}catch(r){if(r instanceof U)return e.json({error:r.message},r.status);throw r}return mt(e,async r=>{await n.run({writeData:async l=>{await r.writeSSE({data:JSON.stringify(l)})},writeDone:async()=>{await r.writeSSE({data:"[DONE]"})}},e.req.raw.signal)})});var Bn=te;export{U as ChatRequestError,mn as cancelClaudeConversation,$t as claudeActivitySnapshot,Bn as default,jn as handleClaudeChatStream,Ve as prepareClaudeChatStream};
|
package/dist/schemas.d.ts
CHANGED
|
@@ -113,6 +113,14 @@ export declare const ChatForkSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
113
113
|
sessionId: z.ZodString;
|
|
114
114
|
messageId: z.ZodString;
|
|
115
115
|
}, z.core.$strict>]>;
|
|
116
|
+
export declare const AgentEffortSchema: z.ZodEnum<{
|
|
117
|
+
low: "low";
|
|
118
|
+
medium: "medium";
|
|
119
|
+
high: "high";
|
|
120
|
+
xhigh: "xhigh";
|
|
121
|
+
max: "max";
|
|
122
|
+
}>;
|
|
123
|
+
export type AgentEffort = z.infer<typeof AgentEffortSchema>;
|
|
116
124
|
export declare const ChatBodySchema: z.ZodObject<{
|
|
117
125
|
conversationId: z.ZodOptional<z.ZodString>;
|
|
118
126
|
fork: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -123,6 +131,13 @@ export declare const ChatBodySchema: z.ZodObject<{
|
|
|
123
131
|
messageId: z.ZodString;
|
|
124
132
|
}, z.core.$strict>]>>;
|
|
125
133
|
model: z.ZodString;
|
|
134
|
+
effort: z.ZodDefault<z.ZodEnum<{
|
|
135
|
+
low: "low";
|
|
136
|
+
medium: "medium";
|
|
137
|
+
high: "high";
|
|
138
|
+
xhigh: "xhigh";
|
|
139
|
+
max: "max";
|
|
140
|
+
}>>;
|
|
126
141
|
message: z.ZodObject<{
|
|
127
142
|
id: z.ZodOptional<z.ZodString>;
|
|
128
143
|
role: z.ZodOptional<z.ZodEnum<{
|
package/dist/schemas.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z as t}from"zod";const o=t.object({type:t.literal("text"),text:t.string()}),e=t.object({type:t.literal("file"),mediaType:t.string(),filename:t.string().optional(),url:t.string()}),a=t.object({type:t.literal("step-start")}),n=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.string(),title:t.string().optional(),state:t.string(),input:t.unknown().optional(),output:t.unknown().optional()}),r=t.object({answers:t.record(t.string(),t.string())}),
|
|
1
|
+
import{z as t}from"zod";const o=t.object({type:t.literal("text"),text:t.string()}),e=t.object({type:t.literal("file"),mediaType:t.string(),filename:t.string().optional(),url:t.string()}),a=t.object({type:t.literal("step-start")}),n=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.string(),title:t.string().optional(),state:t.string(),input:t.unknown().optional(),output:t.unknown().optional()}),r=t.object({answers:t.record(t.string(),t.string())}),l=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.enum(["AskUserQuestion","ask_user_question"]),state:t.literal("output-available"),output:r}),s=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.enum(["ExitPlanMode","exit_plan_mode"]),state:t.literal("output-available"),output:t.unknown()}),i=t.object({id:t.string(),approved:t.boolean(),reason:t.string().optional()}),p=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.string(),state:t.literal("approval-responded"),input:t.unknown().optional(),approval:i}),c=t.union([l,s,p]),m=t.looseObject({type:t.string()}),u=t.strictObject({threadId:t.string().min(1),turnId:t.string().min(1)}),g=t.strictObject({sessionId:t.string().min(1),messageId:t.string().min(1)}),h=t.union([u,g]),d=t.enum(["low","medium","high","xhigh","max"]),S=t.object({conversationId:t.string().optional(),fork:h.optional(),model:t.string(),effort:d.default("medium"),message:t.object({id:t.string().optional(),role:t.enum(["user","assistant"]).optional(),parts:t.array(t.union([o,e,a,c,n,m]))})});export{c as AgentAnswerToolPartSchema,d as AgentEffortSchema,l as AskUserQuestionToolPartSchema,S as ChatBodySchema,m as ChatCustomPartSchema,e as ChatFilePartSchema,h as ChatForkSchema,a as ChatStepStartPartSchema,o as ChatTextPartSchema,n as ChatToolPartSchema,r as ClaudeAskUserQuestionOutputSchema,g as ClaudeChatForkSchema,u as CodexChatForkSchema,s as ExitPlanModeToolPartSchema,p as ToolApprovalPartSchema,i as ToolApprovalSchema};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@messenger-agent/claude-agent",
|
|
3
|
-
"version": "0.26.0-alpha.
|
|
3
|
+
"version": "0.26.0-alpha.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"ws": "^8.21.0",
|
|
20
20
|
"yaml": "^2.9.0",
|
|
21
21
|
"zod": "^4.4.3",
|
|
22
|
-
"@messenger-agent/shared": "0.26.0-alpha.
|
|
22
|
+
"@messenger-agent/shared": "0.26.0-alpha.5"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/ws": "^8.18.1"
|