@messenger-agent/claude-agent 0.26.0-alpha.3 → 0.26.0-alpha.6

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/app.js CHANGED
@@ -1 +1 @@
1
- import{Hono as e}from"hono";import{logger as a}from"hono/logger";import i from"./routes/chat.js";import{logger as m}from"@messenger-agent/shared/logger";import{agentAuthMiddleware as p}from"@messenger-agent/shared/agent-auth";import{appConfig as n}from"./config.js";import{installAgentActivityResponder as f}from"@messenger-agent/shared/agent-activity";import{claudeActivitySnapshot as g}from"./routes/chat.js";const o=new e;f("claude",g),o.use(a((t,...r)=>m.info(t,...r))),o.get("/health",t=>t.json({status:"ok",agent:"claude"})),o.use("/*",p(n.authTokens)),o.route("/",i);var v=o;export{v as default};
1
+ import{Hono as e}from"hono";import r from"./routes/chat.js";import{infoRequestLogger as a}from"@messenger-agent/shared/http-logger";import{agentAuthMiddleware as i}from"@messenger-agent/shared/agent-auth";import{appConfig as m}from"./config.js";import{installAgentActivityResponder as p}from"@messenger-agent/shared/agent-activity";import{claudeActivitySnapshot as n}from"./routes/chat.js";const t=new e;p("claude",n),t.use(a(["/health"])),t.get("/health",o=>o.json({status:"ok",agent:"claude"})),t.use("/*",i(m.authTokens)),t.route("/",r);var g=t;export{g as default};
@@ -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/claude.d.ts CHANGED
@@ -1 +1 @@
1
- export { query, type Options, type PermissionMode, type Query, type SDKMessage, type SDKResultMessage, type SDKUserMessage, } from "@anthropic-ai/claude-agent-sdk";
1
+ export { getSessionInfo, query, type Options, type PermissionMode, type Query, type SDKMessage, type SDKResultMessage, type SDKUserMessage, } from "@anthropic-ai/claude-agent-sdk";
package/dist/claude.js CHANGED
@@ -1 +1 @@
1
- import{query as o}from"@anthropic-ai/claude-agent-sdk";export{o as query};
1
+ import{getSessionInfo as r,query as f}from"@anthropic-ai/claude-agent-sdk";export{r as getSessionInfo,f as query};
package/dist/config.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type AgentAuthConfig, type AgentWorkspacesConfig, type GitInitConfig } from "@messenger-agent/shared/agent-config";
2
2
  import { type LogLevel } from "@messenger-agent/shared/logger";
3
+ import { type ScheduleServiceConfig } from "@messenger-agent/shared/schedule-tools";
3
4
  export type AppConfig = {
4
5
  configPath: string;
5
6
  logLevel: LogLevel;
@@ -17,6 +18,7 @@ export type AppConfig = {
17
18
  askTimeoutMs: number;
18
19
  sessionIdleTimeoutMs: number;
19
20
  };
21
+ schedule: ScheduleServiceConfig;
20
22
  tunnel: {
21
23
  enabled: boolean;
22
24
  serverUrl?: string;
package/dist/config.js CHANGED
@@ -1 +1 @@
1
- import{existsSync as h,readFileSync as k}from"node:fs";import{tmpdir as g}from"node:os";import{join as r}from"node:path";import{parse as T}from"yaml";import{z as e}from"zod";import{normalizeOptional as o,parseAgentAuthConfig as f,parseAgentWorkspacesConfig as b,parseGitInitConfig as v}from"@messenger-agent/shared/agent-config";import{logger as p,normalizeLogLevel as C,setLogFile as M,setLogLevel as I}from"@messenger-agent/shared/logger";const L="wss://m.elevo.vip/agent-bridge/tunnel",S="https://m.elevo.vip/agent-bridge/llm",U=e.object({log_level:e.string().optional(),port:e.coerce.number().int().positive().optional(),auth_tokens:e.record(e.string(),e.string()).optional(),workspaces:e.array(e.object({id:e.string().optional(),name:e.string().optional(),path:e.string().optional()})).optional(),file_uploads:e.object({temp_dir:e.string().optional()}).optional(),data_dir:e.string().optional(),claude:e.object({port:e.coerce.number().int().positive().optional(),data_dir:e.string().optional(),file_uploads:e.object({temp_dir:e.string().optional()}).optional(),api_key:e.string().optional(),base_url:e.string().optional(),default_model:e.string().optional(),max_turns:e.coerce.number().int().positive().optional(),ask_timeout_ms:e.coerce.number().int().positive().optional(),session_idle_timeout_ms:e.coerce.number().int().positive().optional()}).optional(),gitlab:e.object({ca_cert_path:e.string().optional(),host:e.string().optional()}).optional(),git:e.object({co_authors:e.array(e.string()).optional()}).optional(),tunnel:e.object({enabled:e.boolean().optional(),server_url:e.string().optional(),tunnel_id:e.string().optional(),token:e.string().optional(),reconnect_initial_ms:e.number().int().positive().optional(),reconnect_max_ms:e.number().int().positive().optional(),heartbeat_interval_ms:e.number().int().positive().optional()}).optional()}).loose();function j(){const n=process.env.AGENT_CONFIG_PATH??"./agent-config.yaml";if(!h(n)){const l="/data",m=r(l,"logs","claude-agent.log");return I("info"),M(m),p.warn(`Config file not found at ${n}`),{configPath:n,logLevel:"info",logFile:m,port:3e3,fileUploads:{tempDir:r(g(),"claude-agent-uploads")},dataDir:l,claude:{askTimeoutMs:432e5,sessionIdleTimeoutMs:36e5},tunnel:{enabled:!1,reconnectInitialMs:1e3,reconnectMaxMs:3e4,heartbeatIntervalMs:3e4},...f({}),...b({}),...v({})}}let s;try{s=T(k(n,"utf-8"))}catch(l){p.error(`Failed to parse config file at ${n}:`,l),s={}}const a=U.safeParse(s??{});a.success||p.error(`Invalid config format at ${n}:`,a.error.issues);const t=a.success?a.data:{},c=C(t.log_level),u=o(t.claude?.data_dir)??o(t.data_dir)??"/data",d=r(u,"logs","claude-agent.log"),i=t.tunnel?.enabled??!1,_=o(t.tunnel?.token);return I(c),M(d),{configPath:n,logLevel:c,logFile:d,port:t.claude?.port??t.port??3e3,fileUploads:{tempDir:o(t.claude?.file_uploads?.temp_dir)??o(t.file_uploads?.temp_dir)??r(g(),"claude-agent-uploads")},dataDir:u,claude:{apiKey:o(t.claude?.api_key)??(i?_:void 0),baseUrl:o(t.claude?.base_url)??(i?S:void 0),defaultModel:o(t.claude?.default_model),maxTurns:t.claude?.max_turns,askTimeoutMs:Number.parseInt(process.env.CLAUDE_ASK_TIMEOUT_MS??"",10)||t.claude?.ask_timeout_ms||432e5,sessionIdleTimeoutMs:Number.parseInt(process.env.CLAUDE_SESSION_IDLE_TIMEOUT_MS??"",10)||t.claude?.session_idle_timeout_ms||36e5},tunnel:{enabled:i,serverUrl:o(t.tunnel?.server_url)??(i?L:void 0),tunnelId:o(t.tunnel?.tunnel_id),token:_,reconnectInitialMs:t.tunnel?.reconnect_initial_ms??1e3,reconnectMaxMs:t.tunnel?.reconnect_max_ms??3e4,heartbeatIntervalMs:t.tunnel?.heartbeat_interval_ms??3e4},...f(t),...b(t),...v(t)}}const N=j();export{N as appConfig};
1
+ import{existsSync as y,readFileSync as T}from"node:fs";import{tmpdir as b}from"node:os";import{join as r}from"node:path";import{parse as C}from"yaml";import{z as e}from"zod";import{normalizeOptional as o,parseAgentAuthConfig as v,parseAgentWorkspacesConfig as h,parseGitInitConfig as M}from"@messenger-agent/shared/agent-config";import{logger as p,normalizeLogLevel as S,setLogFile as I,setLogLevel as k}from"@messenger-agent/shared/logger";import{deriveScheduleServiceConfig as U}from"@messenger-agent/shared/schedule-tools";const j="wss://m.elevo.vip/agent-bridge/tunnel",L="https://m.elevo.vip/agent-bridge/llm",x=e.object({log_level:e.string().optional(),port:e.coerce.number().int().positive().optional(),auth_tokens:e.record(e.string(),e.string()).optional(),workspaces:e.array(e.object({id:e.string().optional(),name:e.string().optional(),path:e.string().optional()})).optional(),file_uploads:e.object({temp_dir:e.string().optional()}).optional(),data_dir:e.string().optional(),claude:e.object({port:e.coerce.number().int().positive().optional(),data_dir:e.string().optional(),file_uploads:e.object({temp_dir:e.string().optional()}).optional(),api_key:e.string().optional(),base_url:e.string().optional(),default_model:e.string().optional(),max_turns:e.coerce.number().int().positive().optional(),ask_timeout_ms:e.coerce.number().int().positive().optional(),session_idle_timeout_ms:e.coerce.number().int().positive().optional()}).optional(),schedule:e.object({base_url:e.string().optional(),api_key:e.string().optional()}).optional(),gitlab:e.object({ca_cert_path:e.string().optional(),host:e.string().optional()}).optional(),git:e.object({co_authors:e.array(e.string()).optional()}).optional(),tunnel:e.object({enabled:e.boolean().optional(),server_url:e.string().optional(),tunnel_id:e.string().optional(),token:e.string().optional(),reconnect_initial_ms:e.number().int().positive().optional(),reconnect_max_ms:e.number().int().positive().optional(),heartbeat_interval_ms:e.number().int().positive().optional()}).optional()}).loose();function A(){const n=process.env.AGENT_CONFIG_PATH??"./agent-config.yaml";if(!y(n)){const l="/data",f=r(l,"logs","claude-agent.log");return k("info"),I(f),p.warn(`Config file not found at ${n}`),{configPath:n,logLevel:"info",logFile:f,port:3e3,fileUploads:{tempDir:r(b(),"claude-agent-uploads")},dataDir:l,claude:{askTimeoutMs:432e5,sessionIdleTimeoutMs:36e5},schedule:{},tunnel:{enabled:!1,reconnectInitialMs:1e3,reconnectMaxMs:3e4,heartbeatIntervalMs:3e4},...v({}),...h({}),...M({})}}let s;try{s=C(T(n,"utf-8"))}catch(l){p.error(`Failed to parse config file at ${n}:`,l),s={}}const i=x.safeParse(s??{});i.success||p.error(`Invalid config format at ${n}:`,i.error.issues);const t=i.success?i.data:{},c=S(t.log_level),u=o(t.claude?.data_dir)??o(t.data_dir)??"/data",d=r(u,"logs","claude-agent.log"),a=t.tunnel?.enabled??!1,_=o(t.tunnel?.token),m=o(t.claude?.api_key)??(a?_:void 0),g=o(t.claude?.base_url)??(a?L:void 0);return k(c),I(d),{configPath:n,logLevel:c,logFile:d,port:t.claude?.port??t.port??3e3,fileUploads:{tempDir:o(t.claude?.file_uploads?.temp_dir)??o(t.file_uploads?.temp_dir)??r(b(),"claude-agent-uploads")},dataDir:u,claude:{apiKey:m,baseUrl:g,defaultModel:o(t.claude?.default_model),maxTurns:t.claude?.max_turns,askTimeoutMs:Number.parseInt(process.env.CLAUDE_ASK_TIMEOUT_MS??"",10)||t.claude?.ask_timeout_ms||432e5,sessionIdleTimeoutMs:Number.parseInt(process.env.CLAUDE_SESSION_IDLE_TIMEOUT_MS??"",10)||t.claude?.session_idle_timeout_ms||36e5},schedule:U({baseUrl:o(t.schedule?.base_url),apiKey:o(t.schedule?.api_key)},g,m),tunnel:{enabled:a,serverUrl:o(t.tunnel?.server_url)??(a?j:void 0),tunnelId:o(t.tunnel?.tunnel_id),token:_,reconnectInitialMs:t.tunnel?.reconnect_initial_ms??1e3,reconnectMaxMs:t.tunnel?.reconnect_max_ms??3e4,heartbeatIntervalMs:t.tunnel?.heartbeat_interval_ms??3e4},...v(t),...h(t),...M(t)}}const G=A();export{G as appConfig};
@@ -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;
@@ -1 +1 @@
1
- import{logger as r}from"@messenger-agent/shared/logger";import{query as m}from"./claude.js";import{createInputQueue as T}from"./input-queue.js";import{claudeExecutionPermissionMode as f}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=T();abortController=new AbortController;sdkQuery;idleTimeoutMs;onRecycle;currentTurn;transition=Promise.resolve();idleTimer;pumpStarted=!1;dead=!1;cancelIntent=!1;generation=0;_conversationId;_model;_agentMode;constructor(e){this._conversationId=e.conversationId,this.workdir=e.workdir,this._model=e.model,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=m({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 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.agentMode!==this._agentMode&&(await this.sdkQuery.setPermissionMode?.(n.agentMode==="plan"?"plan":f()),this._agentMode=n.agentMode);const o=++this.generation;let a,d;const u=new Promise((h,c)=>{a=h,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:u}})}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};
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.hasActiveOwner())return this.inputQueue.push(l(e,"next")),{kind:"interjection",generation:this.generation};this.updateManagedTaskContext(n.managedTaskContext),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};
@@ -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;
@@ -1,4 +1,4 @@
1
- import{randomUUID as s}from"node:crypto";import{mkdirSync as v}from"node:fs";import{dirname as E,join as k}from"node:path";import{DatabaseSync as A}from"node:sqlite";import{appConfig as m}from"./config.js";const X=["AskUserQuestion"],B=["ExitPlanMode"],d=new Map,_=k(m.dataDir,"pending-asks.sqlite");v(E(_),{recursive:!0});const i=new A(_);i.exec(`
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 x=i.prepare(`
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
- `),N=i.prepare("SELECT * FROM pending_tools WHERE tool_call_id = ?"),P=i.prepare(`
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
- `),O=i.prepare(`
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 = ?"),I=i.prepare("SELECT * FROM pending_tools ORDER BY updated_at DESC, created_at DESC");function u(e){let n,t;const o=new Promise((r,a)=>{n=r,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,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){x.run(e.toolCallId,e.id,e.kind,e.conversationId,e.workdir,e.model??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=d.get(e.toolCallId);if(n)return n;const t=u(e);return d.set(e.toolCallId,t),t}function p(e){const n=d.get(e)?.record;if(n)return n;const t=N.get(e),o=t?c(t):void 0;if(o)return T(o),o}function f(e){const n=Array.from(d.values(),r=>r.record).filter(r=>r.conversationId===e).sort((r,a)=>a.updatedAt.localeCompare(r.updatedAt))[0];if(n)return n;const t=P.get(e),o=t?c(t):void 0;if(o)return T(o),o}function F(e){const n=d.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,agentMode:e.agentMode,toolName:e.toolName,input:e.input,createdAt:t,updatedAt:t};return d.set(e.toolCallId,u(o)),g(o),o}function S(e){const n=p(e);return n?.kind==="ask_user"?n:void 0}function W(e){const n=f(e);return n?.kind==="ask_user"?n:void 0}function H(e){const n=d.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,agentMode:e.agentMode,toolName:e.toolName,input:e.input,approveId:s(),createdAt:t,updatedAt:t};return d.set(e.toolCallId,u(o)),g(o),o}function C(e){const n=p(e);return n?.kind==="approval"?n:void 0}function b(e){const n=f(e);return n?.kind==="approval"?n:void 0}function J(e){return p(e)}function Y(e){return f(e)}function h(e,n){L(e,n)}function L(e,n){const t=new Date().toISOString();let o=!1;for(const r of d.values())r.record.conversationId===e&&(r.record.conversationId=n,r.record.updatedAt=t,o=!0);o&&O.run(n,t,e)}function G(e){return d.get(e)?.promise}function Q(e,n){const t=d.get(e)??(S(e)?d.get(e):void 0);return!t||t.record.kind!=="ask_user"?!1:(d.delete(e),l.run(e),t.resolve(n),!0)}function K(e){return d.get(e)?.promise}function V(e,n){const t=d.get(e)??(C(e)?d.get(e):void 0);return!t||t.record.kind!=="approval"?!1:(d.delete(e),l.run(e),t.resolve(n),!0)}function q(e,n={}){w(e,n)}function w(e,n={}){const t=d.get(e);d.delete(e),l.run(e),t&&n.rejectWait&&t.reject(new Error(`Pending client tool was cancelled: ${e}`))}function $(){return D().filter(e=>e.kind==="ask_user")}function D(){const e=new Map;for(const n of I.all()){const t=c(n);t&&e.set(t.toolCallId,t)}for(const n of d.values())e.set(n.record.toolCallId,n.record);return Array.from(e.values()).sort((n,t)=>t.updatedAt.localeCompare(n.updatedAt))}function z(){d.clear(),i.close()}export{B as PENDING_APPROVAL_TOOL_NAMES,X as PENDING_ASK_TOOL_NAMES,V as answerPendingApproval,Q as answerPendingAsk,z as closePendingToolsDatabaseForTest,q as deletePendingAsk,w as deletePendingClientTool,b as findPendingApprovalByConversation,W as findPendingAskByConversation,Y as findPendingClientToolByConversation,$ as listPendingAsks,D as listPendingClientTools,C as loadPendingApproval,S as loadPendingAsk,J as loadPendingClientTool,H as savePendingApproval,F as savePendingAsk,h as updatePendingAskConversation,L as updatePendingClientToolConversation,K as waitPendingApproval,G as waitPendingAsk};
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};
@@ -1,6 +1,8 @@
1
- import{existsSync as o,readFileSync as m}from"node:fs";import{fileURLToPath as s}from"node:url";import{logger as r}from"@messenger-agent/shared/logger";const d=[s(new URL("./assets/codex-home/AGENTS.md",import.meta.url)),s(new URL("../../../assets/codex-home/AGENTS.md",import.meta.url)),"/app/assets/codex-home/AGENTS.md"],i=["search_managed_tasks","get_managed_task","create_managed_task","update_managed_task","apply_managed_task_patch","delete_managed_task"],l=["## Claude Managed Task Tools","","When the user asks to create, update, inspect, continue, summarize, or delete managed tasks, use the managed task MCP tools. The available tool basenames are: "+i.map(e=>`\`${e}\``).join(", ")+". Claude may expose them with an MCP namespace such as `mcp__managed_tasks__<tool>`.",""].join(`
2
- `),_=["## Response Style","","Do not use emoji in responses.","Use Markdown headings, bold, and italic formatting sparingly.","Other Markdown formatting, such as lists, inline code, links, and code blocks, may be used as needed.",""].join(`
3
- `),n=`${l}
4
- ${_}`;function c(e){const a=[e??process.env.CLAUDE_MEMORY_TEMPLATE_PATH,...d].find(t=>!!(t&&o(t)));return a?`${m(a,"utf-8").trimEnd()}
1
+ import{existsSync as o,readFileSync as r}from"node:fs";import{fileURLToPath as s}from"node:url";import{logger as i}from"@messenger-agent/shared/logger";const c=[s(new URL("./assets/codex-home/AGENTS.md",import.meta.url)),s(new URL("../../../assets/codex-home/AGENTS.md",import.meta.url)),"/app/assets/codex-home/AGENTS.md"],d=["search_managed_tasks","get_managed_task","create_managed_task","update_managed_task","apply_managed_task_patch","delete_managed_task"],m=["## Claude Managed Task Tools","","When the user asks to create, update, inspect, continue, summarize, or delete managed tasks, use the managed task MCP tools. The available tool basenames are: "+d.map(e=>`\`${e}\``).join(", ")+". Claude may expose them with an MCP namespace such as `mcp__managed_tasks__<tool>`.",""].join(`
2
+ `),l=["## Response Style","","Do not use emoji in responses.","Use Markdown headings, bold, and italic formatting sparingly.","Other Markdown formatting, such as lists, inline code, links, and code blocks, may be used as needed.",""].join(`
3
+ `),u=["## Schedule Tool","","Use the single schedule MCP tool to create, list, inspect, update, pause, resume, or cancel schedules in the current trusted Matrix context. Select the action inside `input.action`; never ask for or invent a Room ID, actor ID, source event, or service credential. After create or update succeeds, repeat the service's normalized rule, absolute next run time, IANA timezone, message, and mention MXIDs to the user so relative times and recurrence are unambiguous.",""].join(`
4
+ `),n=`${m}
5
+ ${u}
6
+ ${l}`;function _(e){const t=[e??process.env.CLAUDE_MEMORY_TEMPLATE_PATH,...c].find(a=>!!(a&&o(a)));return t?`${r(t,"utf-8").trimEnd()}
5
7
 
6
- ${n}`:(r.warn("Claude platform instructions template not found"),n)}const A=c();export{A as claudePlatformInstructions,c as loadClaudePlatformInstructions};
8
+ ${n}`:(i.warn("Claude platform instructions template not found"),n)}const h=_();export{h as claudePlatformInstructions,_ as loadClaudePlatformInstructions};
@@ -1,8 +1,8 @@
1
- import{randomUUID as Ue}from"node:crypto";import{existsSync as lt,mkdirSync as dt}from"node:fs";import{Hono as ut}from"hono";import{HTTPException as ke}from"hono/http-exception";import{zValidator as ct}from"@hono/zod-validator";import{streamSSE as pt}from"hono/streaming";import{claudePlatformInstructions as ft}from"../platform-instructions.js";import{logger as B}from"@messenger-agent/shared/logger";import{appConfig as y}from"../config.js";import{resolveAgentWorkdir as mt,resolveAgentWorkspaceRoot as wt}from"@messenger-agent/shared/agent-workspaces";import{isManagedTaskToolName as $e}from"@messenger-agent/shared/managed-task-tools";import{saveUploadedFilePart as yt}from"@messenger-agent/shared/uploaded-files";import{answerPendingApproval as qe,answerPendingAsk as Le,deletePendingClientTool as We,findPendingClientToolByConversation as vt,listPendingClientTools as Fe,loadPendingClientTool as kt,savePendingAsk as gt,savePendingApproval as Tt,updatePendingAskConversation as _t,waitPendingApproval as It,waitPendingAsk as ht}from"../pending-asks.js";import{AgentAnswerToolPartSchema as Ct,ChatBodySchema as xt}from"../schemas.js";import{createTaskAggregator as bt}from"../task-aggregator.js";import{createManagedTaskMcpServer as St,MANAGED_TASK_MCP_SERVER_NAME as He}from"../managed-task-mcp.js";import{claudeExecutionPermissionMode as At,claudePermissionOptions as Mt}from"../permission.js";import{claudeContextSnapshot as Et,claudeTokenUsage as Pt}from"../token-usage.js";import{SessionManager as Dt}from"../session-manager.js";import{getLlmProxyBinding as Ot,moveLlmProxyBinding as Rt,setLlmProxyBinding as Nt}from"../llm-proxy-bindings.js";const ee=new ut,X=new Dt(()=>y.claude.sessionIdleTimeoutMs??36e5),Q=new Set;function jt(e){if($e(e))return!0;const n=`mcp__${He}__`;return e.startsWith(n)&&$e(e.slice(n.length))}function Bt(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 Ut(){const e=new Set(Fe().map(n=>n.conversationId));return{active:Q.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 Xe(e){return e?.trim().toLowerCase()==="plan"?"plan":"default"}function $t(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 qt(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 Lt(e){if(e.type==="text"&&typeof e.text=="string")return e.text;if(qt(e))return yt(e,y.fileUploads.tempDir);if(e.type!=="step-start")throw new ke(400,{message:`Unsupported message part type: ${e.type}`})}async function Wt(e){const r=(await Promise.all(e.map(Lt))).filter(s=>!!(s&&s.trim().length>0)).join(`
2
- `).trim();if(!r)throw new ke(400,{message:"No supported message content found"});return r}function Ft(e){for(const n of e){const r=Ct.safeParse(n);if(r.success)return r.data}}function ge(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(`
1
+ import{randomUUID as Le}from"node:crypto";import{existsSync as pt,mkdirSync as ft}from"node:fs";import{Hono as mt}from"hono";import{HTTPException as ke}from"hono/http-exception";import{zValidator as wt}from"@hono/zod-validator";import{streamSSE as yt}from"hono/streaming";import{claudePlatformInstructions as vt}from"../platform-instructions.js";import{logger as U}from"@messenger-agent/shared/logger";import{appConfig as w}from"../config.js";import{resolveAgentWorkdir as kt,resolveAgentWorkspaceRoot as gt}from"@messenger-agent/shared/agent-workspaces";import{isManagedTaskToolName as We}from"@messenger-agent/shared/managed-task-tools";import{saveUploadedFilePart as Tt}from"@messenger-agent/shared/uploaded-files";import{answerPendingApproval as Fe,answerPendingAsk as He,deletePendingClientTool as Xe,findPendingClientToolByConversation as _t,listPendingClientTools as Qe,loadPendingClientTool as It,savePendingAsk as ht,savePendingApproval as Ct,updatePendingAskConversation as bt,waitPendingApproval as xt,waitPendingAsk as St}from"../pending-asks.js";import{AgentAnswerToolPartSchema as At,ChatBodySchema as Mt}from"../schemas.js";import{createTaskAggregator as Et}from"../task-aggregator.js";import{createManagedTaskMcpServer as Pt,MANAGED_TASK_MCP_SERVER_NAME as Ke}from"../managed-task-mcp.js";import{createScheduleMcpServer as Dt,SCHEDULE_MCP_SERVER_NAME as Rt}from"../schedule-mcp.js";import{claudeExecutionPermissionMode as Nt,claudePermissionOptions as Ot}from"../permission.js";import{claudeContextSnapshot as jt,claudeTokenUsage as Ut}from"../token-usage.js";import{SessionManager as Bt}from"../session-manager.js";import{getLlmProxyBinding as qt,moveLlmProxyBinding as $t,setLlmProxyBinding as Lt}from"../llm-proxy-bindings.js";import{readClaudeSessionTitle as Wt}from"../session-title.js";const te=new mt,K=new Bt(()=>w.claude.sessionIdleTimeoutMs??36e5),J=new Set;function Ft(e){if(We(e))return!0;const n=`mcp__${Ke}__`;return e.startsWith(n)&&We(e.slice(n.length))}function Ht(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 Xt(){const e=new Set(Qe().map(n=>n.conversationId));return{active:J.size,waiting:e.size}}class B extends Error{status;constructor(n,r){super(r),this.status=n,this.name="ChatRequestError"}}const A=new Map;function Je(e){return e?.trim().toLowerCase()==="plan"?"plan":"default"}function Qt(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 Kt(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 Jt(e){if(e.type==="text"&&typeof e.text=="string")return e.text;if(Kt(e))return Tt(e,w.fileUploads.tempDir);if(e.type!=="step-start")throw new ke(400,{message:`Unsupported message part type: ${e.type}`})}async function zt(e){const r=(await Promise.all(e.map(Jt))).filter(l=>!!(l&&l.trim().length>0)).join(`
2
+ `).trim();if(!r)throw new ke(400,{message:"No supported message content found"});return r}function Vt(e){for(const n of e){const r=At.safeParse(n);if(r.success)return r.data}}function ge(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 Qe(e){if(_(e)&&_(e.answers)){const n=Object.entries(e.answers).map(([r,s])=>`- ${r}:${String(s)}`);if(n.length>0)return["User answered previous question:",...n].join(`
5
- `)}return ge(e)}function Ht(e){return typeof e=="string"?e:JSON.stringify(e)}function Xt(e,n){return _(e)&&typeof e.question=="string"?e.question:`Question ${n+1}`}function Ke(e){return _(e)&&Array.isArray(e.questions)?e.questions:[]}function Qt(e,n){const r=Ke(e);return _(n)&&_(n.answers)?Object.fromEntries(Object.entries(n.answers).map(([s,x])=>[s,String(x)])):r.length>0?Object.fromEntries(r.map((s,x)=>[Xt(s,x),ge(n)])):{answer:ge(n)}}function Kt(e,n,r){return n&&n.state==="output-available"?n.output:{answers:r}}function Jt(e,n,r){return n&&n.state==="output-available"?{answers:Qt(e,n.output),output:n.output}:{answers:r}}function zt(e,n){return!e||e.state!=="output-available"?`User answered previous question: ${n}`:Qe(e.output)}function Gt(e){return _(e)&&typeof e.plan=="string"?e.plan:JSON.stringify(e)}function Vt(e){return{approved:!1,reason:e.trim()||void 0}}function Je(e,n,r){return n&&n.state==="approval-responded"?n.approval:{id:e.approveId,...Vt(r)}}function Te(e,n,r){const s=Je(e,n,r);if(s.id!==e.approveId)throw new ke(400,{message:"Tool approval id does not match pending approval"});return{approved:s.approved,reason:s.reason}}function Yt(e,n,r){const s=Te(e,n,r),x=[s.approved?`User approved tool ${e.toolName} plan:`:`User rejected tool ${e.toolName} plan:`,Gt(e.input)];return s.reason&&x.push(`Reason: ${s.reason}`),x.join(`
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){return e==="Agent"||e==="Task"}function sn(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 ln(e){return"session_id"in e?e.session_id:void 0}function dn(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 un(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 cn(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 pn(n)?e.json({success:!0}):e.json({error:$t(n)},404)});function pn(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=un(n),Ge=cn(n);let $,_e;try{$=nn(s,r),_e=wt(y,s)}catch(I){throw new U(400,I instanceof Error?I.message:"Invalid workspace")}if(r&&!lt($))throw new U(400,`Workdir not found: ${$}`);if(dt($,{recursive:!0}),e.fork&&!("sessionId"in e.fork))throw new U(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,q=l&&!m?l.conversationId:e.conversationId,te=C(n,"X-Elevo-LLM-Binding")?.trim()||void 0;let M=K?void 0:X.get(q);const ne=M?.llmProxyBinding??Ot(q);if(te&&ne&&te!==ne)throw new U(409,"LLM proxy binding does not match the existing conversation");const P=ne??te;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 Ie=e.model||y.claude.defaultModel,J=l&&!m?l.workdir:$,L=l?.kind==="approval"&&Te(l,f,b).approved?"default":l?.agentMode?Xe(l.agentMode):Xe(C(n,"X-Matrix-Agent-Mode")),D=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){B.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=q??Ue();let w=z,Ce=!1,xe=!1,oe=!1,O=new Set,R=new Set;const re=new Map,ae=new Map,ie=new Map;let se=!1,le=!1,de,ue="stop",ce,pe,N,be=new Set,Se=!1,T;const E=bt();let G=!1,Ve=0,j=!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()=>{N||(N={activityId:Ue()},await d({type:"data",kind:"compact",data:{phase:"start",activityId:N.activityId}}))},we=async(t,a={})=>{if(!N)return;const i=N;N=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 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,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 O)await d({type:"text-end",id:t});O=new Set},ot=async()=>{for(const t of R)await d({type:"reasoning-end",id:t});R=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),j=!0,W?.removeEventListener("abort",Z),o&&await d({type:"tool-approval-request",toolCallId:t,approveId:o.approveId}),await Ee(),S=setTimeout(()=>{B.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=>{O.has(t)||(O.add(t),await d({type:"text-start",id:t}))},Oe=async t=>{R.has(t)||(R.add(t),await d({type:"reasoning-start",id:t}))},rt=t=>{if(t===w)return;const a=w;w=t,X.bind(k,t),Rt(a,t,P),_t(a,t);const i=A.get(a);i&&(A.delete(a),A.set(t,i))},Re=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,j=!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)},Ne=()=>{me&&(A.get(w)?.dispose(),A.delete(w));for(const t of fe)We(t,{rejectWait:!0})},at=async()=>(await H(ue),Ne(),F(),!0);Me();const it=async(t,a,i)=>{const{toolUseID:o}=i;if(on(t)){gt({conversationId:w,toolCallId:o,workdir:J,model:D,agentMode:L,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:D,agentMode:L,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 an(t)?{behavior:"allow",updatedInput:{...a,model:D},toolUseID:o}:{behavior:"allow",toolUseID:o}},st=async t=>{if(sn(t))return!1;const a=ln(t);if(a&&(await Re(a),E.setSessionId(a)),j)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 Oe(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){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(),le=!0;const u=ae.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":{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 Oe(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(dn(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}`}),at()}}return!1},ye={threadRef:x,matrixEvent:Ge},k=M??X.create({conversationId:z,workdir:J,model:D,agentMode:L,managedTaskContext:ye,llmProxyBinding:P,buildOptions:(t,a,i)=>({abortController:t,cwd:J,includePartialMessages:!0,model:D,maxTurns:y.claude.maxTurns,systemPrompt:{type:"preset",preset:"claude_code",append:ft},...Mt(L),tools:{type:"preset",preset:"claude_code"},mcpServers:{[He]:St({workspaceRoot:_e,context:i})},disallowedTools:["EnterWorktree","ExitWorktree"],...K?{resume:K.sessionId,resumeSessionAt:K.messageId,forkSession:!0}:q?{resume:q}: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"}})});Nt(z,P),k.updateManagedTaskContext(ye);const Z=()=>k.abort();let je=!1;try{g&&m&&(await m.attach({writeData:async()=>{},writeDone:async()=>{}}),g.kind==="ask_user"?Le(g.toolCallId,{interrupted:!0}):qe(g.toolCallId,{interrupted:!0}),await m.done),l&&(!m||g)&&(l.kind==="ask_user"?await d(g?{type:"tool-output-error",toolCallId:l.toolCallId,toolName:l.toolName,errorText:"Question interrupted by text response"}:{type:"tool-output-available",toolCallId:l.toolCallId,output:Kt(l,f,b)}):await d(g?{type:"tool-output-error",toolCallId:l.toolCallId,toolName:l.toolName,errorText:"Approval interrupted by text response"}:{type:"tool-output-available",toolCallId:l.toolCallId,output:Je(l,f,b)}),(!g||!m)&&We(l.toolCallId));const t=l&&!m&&!g?l.kind==="ask_user"?zt(f,b):Yt(l,f,b):b,a=await k.reserveTurn(t,st,it,{model:D,agentMode:L,managedTaskContext:ye});if(a.kind==="interjection"){T&&clearTimeout(T),await I.writeDone();return}je=!0,W?.aborted&&Z(),W?.addEventListener("abort",Z,{once:!0}),await Promise.race([a.done,Ze]),!j&&!oe&&!v&&await H(k.wasCancelled||!k.isDead?"stop":"error")}catch(t){v?(B.error("Claude stream failed after downstream closed:",t),F()):(await Re(w),W?.aborted||k.wasCancelled?await H("stop"):k.isDead?await H("error"):(B.error("Claude stream failed:",t),await d({type:"error",errorText:t instanceof Error?t.message:String(t)}),await H("error")))}finally{je&&W?.removeEventListener("abort",Z),T&&clearTimeout(T),Q.delete(he),j||Ne(),j||F()}}}}async function Rn(e,n){await(await ze(e)).run(n,e.signal)}ee.post("/v1/chat/stream",ct("json",xt),async e=>{let n;try{n=await ze({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 pt(e,async r=>{await n.run({writeData:async s=>{await r.writeSSE({data:JSON.stringify(s)})},writeDone:async()=>{await r.writeSSE({data:"[DONE]"})}},e.req.raw.signal)})});var Nn=ee;export{U as ChatRequestError,pn as cancelClaudeConversation,Ut as claudeActivitySnapshot,Nn as default,Rn as handleClaudeChatStream,ze as prepareClaudeChatStream};
4
+ `)}return JSON.stringify(e)}function ze(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 ge(e)}function Gt(e){return typeof e=="string"?e:JSON.stringify(e)}function Yt(e,n){return _(e)&&typeof e.question=="string"?e.question:`Question ${n+1}`}function Ve(e){return _(e)&&Array.isArray(e.questions)?e.questions:[]}function Zt(e,n){const r=Ve(e);return _(n)&&_(n.answers)?Object.fromEntries(Object.entries(n.answers).map(([l,b])=>[l,String(b)])):r.length>0?Object.fromEntries(r.map((l,b)=>[Yt(l,b),ge(n)])):{answer:ge(n)}}function en(e,n,r){return n&&n.state==="output-available"?n.output:{answers:r}}function tn(e,n,r){return n&&n.state==="output-available"?{answers:Zt(e,n.output),output:n.output}:{answers:r}}function nn(e,n){return!e||e.state!=="output-available"?`User answered previous question: ${n}`:ze(e.output)}function on(e){return _(e)&&typeof e.plan=="string"?e.plan:JSON.stringify(e)}function rn(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,...rn(r)}}function Te(e,n,r){const l=Ge(e,n,r);if(l.id!==e.approveId)throw new ke(400,{message:"Tool approval id does not match pending approval"});return{approved:l.approved,reason:l.reason}}function an(e,n,r){const l=Te(e,n,r),b=[l.approved?`User approved tool ${e.toolName} plan:`:`User rejected tool ${e.toolName} plan:`,on(e.input)];return l.reason&&b.push(`Reason: ${l.reason}`),b.join(`
6
+ `)}function sn(e){return!!(e&&e.state==="output-available"&&(e.toolName==="AskUserQuestion"||e.toolName==="ask_user_question"))}function ln(e){return!!(e&&e.state==="approval-responded")}async function dn(e,n){return e?e.state==="approval-responded"?e.approval.reason??"":ze(e.output):zt(n)}function un(e,n){return kt(w,e,n)}function cn(e){return e==="AskUserQuestion"}function pn(e){return e==="ExitPlanMode"}function fn(e){return e==="Agent"||e==="Task"}function mn(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 wn(e){return"session_id"in e?e.session_id:void 0}function yn(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 vn(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 kn(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 gn(n)?e.json({success:!0}):e.json({error:Qt(n)},404)});function gn(e){return K.cancel(e)}te.get("/admin/status",e=>{const n=Qe().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=Xt();return e.json({activeTaskCount:r.active,waitingClientToolCount:n.length,clientToolWaits:n})});async function Ye({body:e,headers:n}){const r=C(n,"X-Matrix-Workdir"),l=C(n,"X-Matrix-Workspace-ID"),b=vn(n),Ze=kn(n);let q,_e;try{q=un(l,r),_e=gt(w,l)}catch(I){throw new B(400,I instanceof Error?I.message:"Invalid workspace")}if(r&&!pt(q))throw new B(400,`Workdir not found: ${q}`);if(ft(q,{recursive:!0}),e.fork&&!("sessionId"in e.fork))throw new B(400,"Claude fork requires sessionId and messageId");const z=e.fork&&"sessionId"in e.fork?e.fork:void 0,f=Vt(e.message.parts),s=f&&(sn(f)||ln(f))?It(f.toolCallId):e.conversationId?_t(e.conversationId):void 0,m=s?A.get(s.conversationId):void 0,x=await dn(f,e.message.parts),k=f?void 0:s,$=s&&!m?s.conversationId:e.conversationId,ne=C(n,"X-Elevo-LLM-Binding")?.trim()||void 0;let M=z?void 0:K.get($);const oe=M?.llmProxyBinding??qt($);if(ne&&oe&&ne!==oe)throw new B(409,"LLM proxy binding does not match the existing conversation");const E=oe??ne;if(M&&E&&!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||w.claude.defaultModel,he=e.effort,L=s&&!m?s.workdir:q,W=s?.kind==="approval"&&Te(s,f,x).approved?"default":s?.agentMode?Je(s.agentMode):Je(C(n,"X-Matrix-Agent-Mode")),D=s&&!m?s.model??Ie:Ie,F=s&&!m?s.effort??he:he;return{run:async(I,H)=>{if(s&&m&&!k){const t={};J.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}),s.kind==="ask_user")He(s.toolCallId,tn(s.input,f,x));else{const c=Te(s,f,x);c.approved&&await K.get(s.conversationId)?.setPermissionMode(Nt()),Fe(s.toolCallId,c)}await m.done}catch(c){U.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),J.delete(t)}return}const Ce={};J.add(Ce);const V=$??Le();let y=V,be=!1,xe=!1,re=!1,R=new Set,N=new Set;const ae=new Map,ie=new Map,se=new Map;let le=!1,de=!1,ue,ce="stop",pe,fe,O,Se=new Set,Ae=!1,g;const P=Et();let G=!1,et=0,j=!1;const me=new Set;let v=!1,Y,we=!1,S,X;const tt=new Promise(t=>{X=t});let Me;const nt=new Promise(t=>{Me=t}),Ee=()=>{g=setTimeout(()=>{d({type:"heartbeat"}).catch(()=>{})},6e4)},ot=async t=>{g&&clearTimeout(g),await I.writeData(t),v||Ee()};Y={writeData:async t=>{v||await ot(t)},writeDone:async()=>{v||(v=!0,g&&(clearTimeout(g),g=void 0),await I.writeDone())}};const d=async t=>{v||await Y.writeData(t)},Pe=async()=>{v||(await Y.writeDone(),v=!0)},rt=async()=>{O||(O={activityId:Le()},await d({type:"data",kind:"compact",data:{phase:"start",activityId:O.activityId}}))},ye=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}})},Q=async t=>{if(!(re||v)){re=!0;for(const a of R)await d({type:"text-end",id:a});R=new Set;for(const a of N)await d({type:"reasoning-end",id:a});N=new Set,xe&&(t==="stop"&&pe&&await d({type:"data",kind:"token_usage",data:pe}),await d({type:"finish-step"})),await d({type:"finish",finishReason:t}),await Pe()}};let De;const at=async t=>{const a=await Wt(t,L);!a||a===De||(De=a,await d({type:"data",kind:"session_title",data:{agentType:"claude",sessionId:t,title:a}}))},it=async()=>{for(const t of R)await d({type:"text-end",id:t});R=new Set},st=async()=>{for(const t of N)await d({type:"reasoning-end",id:t});N=new Set},Z=async()=>{await it(),await st()},h=async()=>{if(!G)return;G=!1,P.clearDirty(),await Z();const t=`todo-${V}-${et++}`;await d({type:"tool-input-available",toolCallId:t,toolName:"TodoWrite",input:P.snapshot()}),await d({type:"tool-output-available",toolCallId:t,output:"Task updated"})},Re=async(t,a,i,o)=>{me.has(t)||(me.add(t),j=!0,H?.removeEventListener("abort",ee),o&&await d({type:"tool-approval-request",toolCallId:t,approveId:o.approveId}),await Pe(),S=setTimeout(()=>{U.warn(`Claude ${a} timed out after ${w.claude.askTimeoutMs}ms`,{conversationId:y,toolCallId:t}),A.delete(y),T.abort(),X()},w.claude.askTimeoutMs),S.unref?.(),Me())},Ne=async t=>{R.has(t)||(R.add(t),await d({type:"text-start",id:t}))},Oe=async t=>{N.has(t)||(N.add(t),await d({type:"reasoning-start",id:t}))},lt=t=>{if(t===y)return;const a=y;y=t,K.bind(T,t),$t(a,t,E),bt(a,t);const i=A.get(a);i&&(A.delete(a),A.set(t,i))},je=async t=>{be||(be=!0,lt(t),we||(we=!0,A.set(t,{attach:async a=>{S&&(clearTimeout(S),S=void 0),Y=a,v=!1,j=!1},done:tt,dispose:()=>{S&&(clearTimeout(S),S=void 0)}})),await d({type:"start",messageMetadata:{conversationId:t,threadId:t}}),await d({type:"start-step"}),xe=!0)},Ue=()=>{we&&(A.get(y)?.dispose(),A.delete(y));for(const t of me)Xe(t,{rejectWait:!0})},dt=async()=>(await Q(ce),Ue(),X(),!0);Ee();const ut=async(t,a,i)=>{const{toolUseID:o}=i;if(cn(t)){ht({conversationId:y,toolCallId:o,workdir:L,model:D,effort:F,agentMode:W,toolName:"AskUserQuestion",input:a}),await Re(o,"AskUserQuestion",a);const p=await St(o);return p?"interrupted"in p?{behavior:"deny",message:"Question interrupted by text response",interrupt:!0,toolUseID:o}:{behavior:"allow",updatedInput:{...a,questions:Ve(a),answers:p.answers},toolUseID:o}:{behavior:"deny",message:`${t} requires user input; session will resume after user responds.`,toolUseID:o}}if(pn(t)){const p=Ct({conversationId:y,toolCallId:o,workdir:L,model:D,effort:F,agentMode:W,toolName:"ExitPlanMode",input:a});await Re(o,"ExitPlanMode",a,p);const u=await xt(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 fn(t)?{behavior:"allow",updatedInput:{...a,model:D},toolUseID:o}:{behavior:"allow",toolUseID:o}},ct=async t=>{if(mn(t))return!1;const a=wn(t);if(a&&(await je(a),P.setSessionId(a)),t.type==="system"&&t.subtype==="background_tasks_changed")return Se=new Set(t.tasks.map(i=>i.task_id)),!1;if(j)return!1;switch(t.type){case"system":return t.subtype==="status"?(t.status==="compacting"&&await rt(),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 i=t.event;switch(i.type){case"message_start":{ue=i.message.id,le=!1,de=!1;break}case"content_block_start":{const o=`${ue??t.session_id}:${i.index}`;i.content_block.type==="text"?(await h(),ae.set(o,t.uuid),await Ne(t.uuid)):i.content_block.type==="thinking"&&(await h(),ie.set(o,t.uuid),await Oe(t.uuid));break}case"content_block_delta":{const o=i.delta,p=`${ue??t.session_id}:${i.index}`;if(o.type==="text_delta"){await h(),le=!0;const u=ae.get(p);if(!u){U.warn("Ignoring Claude text delta without content_block_start",{conversationId:y,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){U.warn("Ignoring Claude reasoning delta without content_block_start",{conversationId:y,blockKey:p});break}await d({type:"reasoning-delta",id:u,delta:o.thinking})}break}case"content_block_stop":break}return!1}case"assistant":{fe=jt(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 i=t.message.content;if(typeof i=="string")break;for(const o of i)switch(o.type){case"thinking":{if(de||!o.thinking)break;await h(),await Oe(t.uuid),await d({type:"reasoning-delta",id:t.uuid,delta:o.thinking});break}case"text":{if(le||!o.text)break;await h(),await Ne(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),P.isTaskTool(o.name)){P.applyToolUse(o.id,o.name,o.input)&&(G=!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 i=t.message.content;if(typeof i=="string")break;const o=i.filter(u=>u.type==="tool_result"),p=o.length===1?Ht(t.tool_use_result):void 0;for(const u of o){const c=u.tool_use_id,ve=u.content;if(P.isTaskToolCall(c)){P.applyToolResult(c,ve)&&(G=!0);continue}if(await h(),u.is_error===!0)await d({type:"tool-output-error",toolCallId:c,errorText:Gt(ve)});else{const $e=se.get(c);await d({type:"tool-output-available",toolCallId:c,output:$e&&Ft($e)&&p!==void 0?p:ve})}se.delete(c)}return!1}case"result":{if(Se.size>0)return t.origin?.kind!=="task-notification"&&(Ae=!0),!1;if(yn(t)&&!Ae)return!1;ce=t.subtype==="success"||T.wasCancelled?"stop":"error";const i=Ut(t,fe);return pe=ce==="stop"?i:void 0,await h(),await at(t.session_id),t.subtype!=="success"&&!T.wasCancelled&&await d({type:"error",errorText:t.errors?.filter(o=>o.trim()).join(`
7
+ `)||`Claude Code failed: ${t.subtype}`}),dt()}}return!1},Be={threadRef:b,matrixEvent:Ze,llmProxyBinding:E},T=M??K.create({conversationId:V,workdir:L,model:D,effort:F,agentMode:W,managedTaskContext:Be,llmProxyBinding:E,buildOptions:(t,a,i)=>({abortController:t,cwd:L,includePartialMessages:!0,model:D,effort:F,maxTurns:w.claude.maxTurns,systemPrompt:{type:"preset",preset:"claude_code",append:vt},...Ot(W),tools:{type:"preset",preset:"claude_code"},mcpServers:{[Ke]:Pt({workspaceRoot:_e,context:i}),[Rt]:Dt({config:w.schedule,context:i})},disallowedTools:["EnterWorktree","ExitWorktree"],...z?{resume:z.sessionId,resumeSessionAt:z.messageId,forkSession:!0}:$?{resume:$}:null,canUseTool:a,env:{...process.env,...w.claude.apiKey?{ANTHROPIC_API_KEY:w.claude.apiKey}:null,...w.claude.baseUrl?{ANTHROPIC_BASE_URL:w.claude.baseUrl}:null,...E?{ANTHROPIC_CUSTOM_HEADERS:[process.env.ANTHROPIC_CUSTOM_HEADERS,`X-Elevo-LLM-Binding: ${E}`].filter(Boolean).join(`
8
+ `)}:null,CLAUDE_AGENT_SDK_CLIENT_APP:"coding-agent/claude-agent"}})});Lt(V,E);const ee=()=>T.abort();let qe=!1;try{k&&m&&(await m.attach({writeData:async()=>{},writeDone:async()=>{}}),k.kind==="ask_user"?He(k.toolCallId,{interrupted:!0}):Fe(k.toolCallId,{interrupted:!0}),await m.done),s&&(!m||k)&&(s.kind==="ask_user"?await d(k?{type:"tool-output-error",toolCallId:s.toolCallId,toolName:s.toolName,errorText:"Question interrupted by text response"}:{type:"tool-output-available",toolCallId:s.toolCallId,output:en(s,f,x)}):await d(k?{type:"tool-output-error",toolCallId:s.toolCallId,toolName:s.toolName,errorText:"Approval interrupted by text response"}:{type:"tool-output-available",toolCallId:s.toolCallId,output:Ge(s,f,x)}),(!k||!m)&&Xe(s.toolCallId));const t=s&&!m&&!k?s.kind==="ask_user"?nn(f,x):an(s,f,x):x,a=await T.reserveTurn(t,ct,ut,{model:D,effort:F,agentMode:W,managedTaskContext:Be});if(a.kind==="interjection"){g&&clearTimeout(g),await I.writeDone();return}qe=!0,H?.aborted&&ee(),H?.addEventListener("abort",ee,{once:!0}),await Promise.race([a.done,nt]),!j&&!re&&!v&&await Q(T.wasCancelled||!T.isDead?"stop":"error")}catch(t){v?(U.error("Claude stream failed after downstream closed:",t),X()):(await je(y),H?.aborted||T.wasCancelled?await Q("stop"):T.isDead?await Q("error"):(U.error("Claude stream failed:",t),await d({type:"error",errorText:t instanceof Error?t.message:String(t)}),await Q("error")))}finally{qe&&H?.removeEventListener("abort",ee),g&&clearTimeout(g),J.delete(Ce),j||Ue(),j||X()}}}}async function Fn(e,n){await(await Ye(e)).run(n,e.signal)}te.post("/v1/chat/stream",wt("json",Mt),async e=>{let n;try{n=await Ye({body:e.req.valid("json"),headers:e.req.raw.headers})}catch(r){if(r instanceof B)return e.json({error:r.message},r.status);throw r}return yt(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 Hn=te;export{B as ChatRequestError,gn as cancelClaudeConversation,Xt as claudeActivitySnapshot,Hn as default,Fn as handleClaudeChatStream,Ye as prepareClaudeChatStream};
@@ -0,0 +1,7 @@
1
+ import { type McpSdkServerConfigWithInstance } from "@anthropic-ai/claude-agent-sdk";
2
+ import { type ScheduleServiceConfig, type ScheduleToolContext } from "@messenger-agent/shared/schedule-tools";
3
+ export declare const SCHEDULE_MCP_SERVER_NAME = "schedule";
4
+ export declare function createScheduleMcpServer(options: {
5
+ config: ScheduleServiceConfig;
6
+ context: ScheduleToolContext;
7
+ }): McpSdkServerConfigWithInstance;
@@ -0,0 +1 @@
1
+ import{createSdkMcpServer as a,tool as c}from"@anthropic-ai/claude-agent-sdk";import{executeScheduleTool as s,SCHEDULE_TOOL_DEFINITION as r,ScheduleToolError as i}from"@messenger-agent/shared/schedule-tools";const u="schedule";function y(t){return a({name:u,version:"0.1.0",instructions:"Manage schedules in the current trusted Matrix context.",alwaysLoad:!0,tools:[c(r.name,r.description,r.schema.shape,async n=>{try{const e=await s(t.config,t.context,n);return{content:[{type:"text",text:JSON.stringify(e)}],...e&&typeof e=="object"&&!Array.isArray(e)?{structuredContent:e}:null}}catch(e){const o=e instanceof i?{error:{code:e.code,message:e.message,retryable:e.retryable,currentRevision:e.currentRevision}}:{error:{code:"service_unavailable",message:e instanceof Error?e.message:String(e)}};return{content:[{type:"text",text:JSON.stringify(o)}],structuredContent:o,isError:!0}}},{alwaysLoad:!0,searchHint:r.name})]})}export{u as SCHEDULE_MCP_SERVER_NAME,y as createScheduleMcpServer};
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())}),s=t.object({type:t.literal("tool"),toolCallId:t.string(),toolName:t.enum(["AskUserQuestion","ask_user_question"]),state:t.literal("output-available"),output:r}),l=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([s,l,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)}),d=t.union([u,g]),x=t.object({conversationId:t.string().optional(),fork:d.optional(),model:t.string(),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,s as AskUserQuestionToolPartSchema,x as ChatBodySchema,m as ChatCustomPartSchema,e as ChatFilePartSchema,d as ChatForkSchema,a as ChatStepStartPartSchema,o as ChatTextPartSchema,n as ChatToolPartSchema,r as ClaudeAskUserQuestionOutputSchema,g as ClaudeChatForkSchema,u as CodexChatForkSchema,l as ExitPlanModeToolPartSchema,p as ToolApprovalPartSchema,i as ToolApprovalSchema};
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};
@@ -0,0 +1 @@
1
+ export declare function readClaudeSessionTitle(sessionId: string, workdir: string): Promise<string | undefined>;
@@ -0,0 +1 @@
1
+ import{getSessionInfo as i}from"./claude.js";import{logger as n}from"@messenger-agent/shared/logger";async function d(e,t){try{return(await i(e,{dir:t}))?.summary.trim()||void 0}catch(r){n.warn(`Failed to read Claude session title for ${e}:`,r);return}}export{d as readClaudeSessionTitle};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@messenger-agent/claude-agent",
3
- "version": "0.26.0-alpha.3",
3
+ "version": "0.26.0-alpha.6",
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.3"
22
+ "@messenger-agent/shared": "0.26.0-alpha.6"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/ws": "^8.18.1"