@corbat-tech/coco 2.36.0 → 2.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -10,7 +10,7 @@ import { z } from 'zod';
10
10
  import * as os4 from 'os';
11
11
  import os4__default, { homedir } from 'os';
12
12
  import * as fs35 from 'fs/promises';
13
- import fs35__default, { mkdir, writeFile, readFile, access, readdir, rm, constants } from 'fs/promises';
13
+ import fs35__default, { mkdir, writeFile, readFile, access, constants, readdir, rm } from 'fs/promises';
14
14
  import JSON5 from 'json5';
15
15
  import * as crypto from 'crypto';
16
16
  import { randomUUID, randomBytes, createHash } from 'crypto';
@@ -40857,9 +40857,6 @@ function getSessionStore() {
40857
40857
  }
40858
40858
  return defaultStore;
40859
40859
  }
40860
- function createSessionStore(config) {
40861
- return new SessionStore(config);
40862
- }
40863
40860
 
40864
40861
  // src/cli/repl/commands/resume.ts
40865
40862
  function formatRelativeTime2(date) {
@@ -52606,7 +52603,7 @@ var repoMapCommand = {
52606
52603
  }
52607
52604
  };
52608
52605
 
52609
- // src/cli/repl/modes.ts
52606
+ // src/runtime/agent-modes.ts
52610
52607
  var AGENT_MODES = {
52611
52608
  ask: {
52612
52609
  id: "ask",
@@ -57374,6 +57371,39 @@ init_providers();
57374
57371
 
57375
57372
  // src/runtime/agent-runtime.ts
57376
57373
  init_env();
57374
+
57375
+ // src/runtime/default-turn-runner.ts
57376
+ var DefaultRuntimeTurnRunner = class {
57377
+ async run(input, context) {
57378
+ const messages = [
57379
+ ...context.session.messages,
57380
+ {
57381
+ role: "user",
57382
+ content: input.content
57383
+ }
57384
+ ];
57385
+ const response = await context.provider.chat(messages, {
57386
+ model: input.options?.model,
57387
+ maxTokens: input.options?.maxTokens,
57388
+ temperature: input.options?.temperature,
57389
+ stopSequences: input.options?.stopSequences,
57390
+ system: context.session.instructions ?? input.options?.system,
57391
+ timeout: input.options?.timeout,
57392
+ signal: input.options?.signal,
57393
+ thinking: input.options?.thinking
57394
+ });
57395
+ return {
57396
+ sessionId: context.session.id,
57397
+ content: response.content,
57398
+ usage: response.usage,
57399
+ model: response.model,
57400
+ mode: context.session.mode
57401
+ };
57402
+ }
57403
+ };
57404
+ function createDefaultRuntimeTurnRunner() {
57405
+ return new DefaultRuntimeTurnRunner();
57406
+ }
57377
57407
  var InMemoryEventLog = class {
57378
57408
  events = [];
57379
57409
  record(type, data = {}) {
@@ -57525,6 +57555,22 @@ var DefaultPermissionPolicy = class {
57525
57555
  }
57526
57556
  return { allowed: true, risk };
57527
57557
  }
57558
+ canExecuteToolInput(mode, tool, input) {
57559
+ if (tool.name !== "run_linter") {
57560
+ return this.canExecuteTool(mode, tool);
57561
+ }
57562
+ const definition = getAgentMode(mode);
57563
+ const fixEnabled = input["fix"] === true;
57564
+ const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
57565
+ if (definition.readOnly && fixEnabled) {
57566
+ return {
57567
+ allowed: false,
57568
+ reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
57569
+ risk: "write"
57570
+ };
57571
+ }
57572
+ return decision;
57573
+ }
57528
57574
  };
57529
57575
  function createPermissionPolicy() {
57530
57576
  return new DefaultPermissionPolicy();
@@ -57566,6 +57612,321 @@ var ProviderRegistry = class {
57566
57612
  function createProviderRegistry() {
57567
57613
  return new ProviderRegistry();
57568
57614
  }
57615
+ function createSessionId() {
57616
+ return `rt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
57617
+ }
57618
+ function cloneSession(session) {
57619
+ return structuredClone(session);
57620
+ }
57621
+ var InMemoryRuntimeSessionStore = class {
57622
+ sessions = /* @__PURE__ */ new Map();
57623
+ create(options = {}) {
57624
+ const now = (/* @__PURE__ */ new Date()).toISOString();
57625
+ const session = {
57626
+ id: options.id ?? createSessionId(),
57627
+ createdAt: now,
57628
+ updatedAt: now,
57629
+ mode: options.mode ?? "ask",
57630
+ messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
57631
+ instructions: options.instructions,
57632
+ metadata: { ...options.metadata }
57633
+ };
57634
+ this.sessions.set(session.id, cloneSession(session));
57635
+ return cloneSession(session);
57636
+ }
57637
+ get(id) {
57638
+ const session = this.sessions.get(id);
57639
+ return session ? cloneSession(session) : void 0;
57640
+ }
57641
+ update(session) {
57642
+ const updated = {
57643
+ ...session,
57644
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
57645
+ messages: session.messages.map((message) => ({ ...message })),
57646
+ metadata: { ...session.metadata }
57647
+ };
57648
+ this.sessions.set(updated.id, cloneSession(updated));
57649
+ return cloneSession(updated);
57650
+ }
57651
+ list() {
57652
+ return [...this.sessions.values()].map(cloneSession);
57653
+ }
57654
+ delete(id) {
57655
+ return this.sessions.delete(id);
57656
+ }
57657
+ };
57658
+ function createRuntimeSessionStore() {
57659
+ return new InMemoryRuntimeSessionStore();
57660
+ }
57661
+
57662
+ // src/runtime/workflow-registry.ts
57663
+ function cloneWorkflow(workflow) {
57664
+ return {
57665
+ ...workflow,
57666
+ checks: [...workflow.checks],
57667
+ steps: workflow.steps.map((step) => ({
57668
+ ...step,
57669
+ requiredTools: [...step.requiredTools]
57670
+ }))
57671
+ };
57672
+ }
57673
+ var WorkflowCatalog = class {
57674
+ workflows = /* @__PURE__ */ new Map();
57675
+ constructor(workflows = DEFAULT_WORKFLOWS) {
57676
+ for (const workflow of workflows) {
57677
+ this.register(workflow);
57678
+ }
57679
+ }
57680
+ register(workflow) {
57681
+ this.workflows.set(workflow.id, cloneWorkflow(workflow));
57682
+ }
57683
+ get(id) {
57684
+ const workflow = this.workflows.get(id);
57685
+ return workflow ? cloneWorkflow(workflow) : void 0;
57686
+ }
57687
+ list() {
57688
+ return [...this.workflows.values()].map(cloneWorkflow).sort((a, b) => a.id.localeCompare(b.id));
57689
+ }
57690
+ createPlan(workflowId, input, eventLog) {
57691
+ const workflow = this.get(workflowId);
57692
+ if (!workflow) {
57693
+ throw new Error(`Unknown workflow: ${workflowId}`);
57694
+ }
57695
+ const plan = {
57696
+ id: `${workflowId}-${Date.now().toString(36)}`,
57697
+ workflowId,
57698
+ input,
57699
+ status: "planned",
57700
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
57701
+ };
57702
+ eventLog?.record("workflow.planned", {
57703
+ workflowId,
57704
+ planId: plan.id,
57705
+ replayable: workflow.replayable,
57706
+ checks: workflow.checks
57707
+ });
57708
+ return plan;
57709
+ }
57710
+ };
57711
+ var DEFAULT_WORKFLOWS = [
57712
+ {
57713
+ id: "architect-editor-verifier",
57714
+ name: "Architect / Editor / Verifier",
57715
+ description: "Plan read-only, apply approved changes, then verify and summarize risks.",
57716
+ inputSchema: "task: string; approvedPlan?: string",
57717
+ outputKind: "patch",
57718
+ replayable: true,
57719
+ checks: ["pnpm check", "diff summary", "review risks"],
57720
+ steps: [
57721
+ {
57722
+ id: "architect",
57723
+ description: "Inspect context and produce a read-only implementation plan.",
57724
+ requiredTools: ["repo_context", "read_file", "git_diff"],
57725
+ risk: "read-only"
57726
+ },
57727
+ {
57728
+ id: "editor",
57729
+ description: "Apply the approved plan without reinterpreting the objective.",
57730
+ requiredTools: ["read_file", "edit_file", "write_file"],
57731
+ risk: "write"
57732
+ },
57733
+ {
57734
+ id: "verifier",
57735
+ description: "Run checks, review diff, and report residual risk.",
57736
+ requiredTools: ["bash_exec", "git_diff", "review_code"],
57737
+ risk: "destructive"
57738
+ }
57739
+ ]
57740
+ },
57741
+ {
57742
+ id: "provider-diagnosis",
57743
+ name: "Provider Diagnosis",
57744
+ description: "Probe provider/model capabilities, endpoint strategy, credentials, and fallbacks.",
57745
+ inputSchema: "provider?: string; model?: string; live?: boolean",
57746
+ outputKind: "json",
57747
+ replayable: true,
57748
+ checks: ["provider capability matrix", "optional live probe"],
57749
+ steps: [
57750
+ {
57751
+ id: "capability",
57752
+ description: "Resolve catalog metadata and runtime endpoint strategy.",
57753
+ requiredTools: [],
57754
+ risk: "read-only"
57755
+ },
57756
+ {
57757
+ id: "fallbacks",
57758
+ description: "Suggest fallback provider/model choices when unsupported.",
57759
+ requiredTools: [],
57760
+ risk: "read-only"
57761
+ }
57762
+ ]
57763
+ },
57764
+ {
57765
+ id: "review-pr",
57766
+ name: "Review PR",
57767
+ description: "Review a branch or PR read-only and emit severity-ranked findings.",
57768
+ inputSchema: "target: string",
57769
+ outputKind: "markdown",
57770
+ replayable: true,
57771
+ checks: ["git diff", "tests gap review", "security review"],
57772
+ steps: [
57773
+ {
57774
+ id: "collect-diff",
57775
+ description: "Collect PR diff and related context.",
57776
+ requiredTools: ["git_diff", "repo_context"],
57777
+ risk: "read-only"
57778
+ },
57779
+ {
57780
+ id: "findings",
57781
+ description: "Produce prioritized findings with file and line references.",
57782
+ requiredTools: ["read_file", "review_code"],
57783
+ risk: "read-only"
57784
+ }
57785
+ ]
57786
+ },
57787
+ {
57788
+ id: "best-of-n",
57789
+ name: "Best Of N",
57790
+ description: "Run multiple isolated attempts, score them, and select a winning patch.",
57791
+ inputSchema: "task: string; attempts: number",
57792
+ outputKind: "patch",
57793
+ replayable: true,
57794
+ checks: ["worktree isolation", "checks pass", "diff risk score"],
57795
+ steps: [
57796
+ {
57797
+ id: "fanout",
57798
+ description: "Create isolated attempts in temporary worktrees.",
57799
+ requiredTools: ["git_status", "bash_exec"],
57800
+ risk: "destructive"
57801
+ },
57802
+ {
57803
+ id: "score",
57804
+ description: "Run checks and compare quality, cost, latency, and diff risk.",
57805
+ requiredTools: ["bash_exec", "git_diff"],
57806
+ risk: "destructive"
57807
+ },
57808
+ {
57809
+ id: "apply-winner",
57810
+ description: "Apply the winning patch only if conservative checks pass.",
57811
+ requiredTools: ["git_diff", "edit_file"],
57812
+ risk: "write"
57813
+ }
57814
+ ]
57815
+ },
57816
+ {
57817
+ id: "release",
57818
+ name: "Release",
57819
+ description: "Follow the project release skill: changelog, version bump, PR, merge, tag, publish verify.",
57820
+ inputSchema: "bump?: patch|minor|major",
57821
+ outputKind: "release",
57822
+ replayable: true,
57823
+ checks: ["pnpm check", "PR checks", "release.yml", "npm view"],
57824
+ steps: [
57825
+ {
57826
+ id: "preflight",
57827
+ description: "Verify branch, clean tree, GitHub auth, and remote state.",
57828
+ requiredTools: ["git_status", "bash_exec"],
57829
+ risk: "destructive"
57830
+ },
57831
+ {
57832
+ id: "version",
57833
+ description: "Update changelog and package versions using the release skill.",
57834
+ requiredTools: ["read_file", "edit_file", "bash_exec"],
57835
+ risk: "destructive"
57836
+ },
57837
+ {
57838
+ id: "publish",
57839
+ description: "Merge release PR, tag main, and verify release workflow outputs.",
57840
+ requiredTools: ["bash_exec"],
57841
+ risk: "destructive"
57842
+ }
57843
+ ]
57844
+ }
57845
+ ];
57846
+ function createWorkflowCatalog(workflows) {
57847
+ return new WorkflowCatalog(workflows);
57848
+ }
57849
+
57850
+ // src/runtime/workflow-engine.ts
57851
+ var WorkflowEngine = class {
57852
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
57853
+ this.catalog = catalog;
57854
+ this.eventLog = eventLog;
57855
+ }
57856
+ catalog;
57857
+ eventLog;
57858
+ handlers = /* @__PURE__ */ new Map();
57859
+ registerHandler(workflowId, handler) {
57860
+ if (!this.catalog.get(workflowId)) {
57861
+ throw new Error(`Unknown workflow: ${workflowId}`);
57862
+ }
57863
+ this.handlers.set(workflowId, handler);
57864
+ }
57865
+ createPlan(workflowId, input) {
57866
+ return this.catalog.createPlan(workflowId, input, this.eventLog);
57867
+ }
57868
+ async run(request) {
57869
+ const workflow = this.catalog.get(request.workflowId);
57870
+ if (!workflow) {
57871
+ throw new Error(`Unknown workflow: ${request.workflowId}`);
57872
+ }
57873
+ const handler = this.handlers.get(request.workflowId);
57874
+ if (!handler) {
57875
+ throw new Error(`No handler registered for workflow: ${request.workflowId}`);
57876
+ }
57877
+ const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
57878
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
57879
+ const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
57880
+ this.eventLog.record("workflow.started", {
57881
+ workflowId: request.workflowId,
57882
+ planId: plan.id,
57883
+ runId
57884
+ });
57885
+ try {
57886
+ const output = await handler(request.input, {
57887
+ workflow,
57888
+ plan,
57889
+ eventLog: this.eventLog
57890
+ });
57891
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
57892
+ const result = {
57893
+ id: runId,
57894
+ workflowId: request.workflowId,
57895
+ status: "completed",
57896
+ output,
57897
+ startedAt,
57898
+ completedAt
57899
+ };
57900
+ this.eventLog.record("workflow.completed", {
57901
+ workflowId: request.workflowId,
57902
+ planId: plan.id,
57903
+ runId
57904
+ });
57905
+ return result;
57906
+ } catch (error) {
57907
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
57908
+ const message = error instanceof Error ? error.message : String(error);
57909
+ this.eventLog.record("workflow.failed", {
57910
+ workflowId: request.workflowId,
57911
+ planId: plan.id,
57912
+ runId,
57913
+ error: message
57914
+ });
57915
+ return {
57916
+ id: runId,
57917
+ workflowId: request.workflowId,
57918
+ status: "failed",
57919
+ output: null,
57920
+ startedAt,
57921
+ completedAt,
57922
+ error: message
57923
+ };
57924
+ }
57925
+ }
57926
+ };
57927
+ function createWorkflowEngine(catalog, eventLog) {
57928
+ return new WorkflowEngine(catalog, eventLog);
57929
+ }
57569
57930
 
57570
57931
  // src/runtime/agent-runtime.ts
57571
57932
  var AgentRuntime = class {
@@ -57573,9 +57934,12 @@ var AgentRuntime = class {
57573
57934
  this.options = options;
57574
57935
  this.providerRegistry = createProviderRegistry();
57575
57936
  this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
57576
- this.sessionStore = options.sessionStore ?? createSessionStore({});
57577
- this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
57937
+ this.sessionStore = options.sessionStore;
57938
+ this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
57578
57939
  this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
57940
+ this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
57941
+ this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
57942
+ this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
57579
57943
  this.providerType = options.providerType;
57580
57944
  this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
57581
57945
  }
@@ -57583,16 +57947,21 @@ var AgentRuntime = class {
57583
57947
  providerRegistry;
57584
57948
  toolRegistry;
57585
57949
  sessionStore;
57950
+ runtimeSessionStore;
57951
+ workflowEngine;
57586
57952
  permissionPolicy;
57587
57953
  eventLog;
57954
+ turnRunner;
57588
57955
  providerType;
57589
57956
  model;
57957
+ provider;
57590
57958
  async initialize() {
57591
57959
  const providerInjected = Boolean(this.options.provider);
57592
57960
  const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
57593
57961
  ...this.options.providerConfig,
57594
57962
  model: this.getModel()
57595
57963
  });
57964
+ this.provider = provider;
57596
57965
  this.publishToGlobalBridge(provider);
57597
57966
  this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
57598
57967
  provider: this.providerType,
@@ -57607,6 +57976,7 @@ var AgentRuntime = class {
57607
57976
  updateProvider(providerType, model2, provider) {
57608
57977
  this.providerType = providerType;
57609
57978
  this.model = model2 ?? getDefaultModel(providerType);
57979
+ this.provider = provider;
57610
57980
  this.publishToGlobalBridge(provider);
57611
57981
  this.eventLog.record("provider.updated", {
57612
57982
  provider: this.providerType,
@@ -57634,7 +58004,276 @@ var AgentRuntime = class {
57634
58004
  modes: listAgentModes()
57635
58005
  };
57636
58006
  }
57637
- assertToolAllowed(mode, toolName) {
58007
+ createSession(options = {}) {
58008
+ const session = this.runtimeSessionStore.create(options);
58009
+ this.eventLog.record("session.created", {
58010
+ sessionId: session.id,
58011
+ mode: session.mode,
58012
+ metadataKeys: Object.keys(session.metadata).sort()
58013
+ });
58014
+ return session;
58015
+ }
58016
+ getSession(sessionId) {
58017
+ return this.runtimeSessionStore.get(sessionId);
58018
+ }
58019
+ listSessions() {
58020
+ return this.runtimeSessionStore.list();
58021
+ }
58022
+ async runTurn(input) {
58023
+ const provider = this.provider;
58024
+ if (!provider) {
58025
+ throw new Error("Runtime provider is not initialized.");
58026
+ }
58027
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
58028
+ if (!session) {
58029
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
58030
+ }
58031
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
58032
+ this.eventLog.record("turn.started", {
58033
+ sessionId: effectiveSession.id,
58034
+ provider: this.providerType,
58035
+ model: this.getModel(),
58036
+ mode: effectiveSession.mode,
58037
+ runtimeApi: true
58038
+ });
58039
+ try {
58040
+ const result = await this.turnRunner.run(input, {
58041
+ runtime: this,
58042
+ session: effectiveSession,
58043
+ provider,
58044
+ toolRegistry: this.toolRegistry,
58045
+ permissionPolicy: this.permissionPolicy,
58046
+ eventLog: this.eventLog
58047
+ });
58048
+ const updatedSession = this.runtimeSessionStore.update({
58049
+ ...effectiveSession,
58050
+ messages: [
58051
+ ...effectiveSession.messages,
58052
+ { role: "user", content: input.content },
58053
+ { role: "assistant", content: result.content }
58054
+ ]
58055
+ });
58056
+ this.eventLog.record("session.updated", {
58057
+ sessionId: updatedSession.id,
58058
+ messages: updatedSession.messages.length
58059
+ });
58060
+ this.eventLog.record("turn.completed", {
58061
+ sessionId: updatedSession.id,
58062
+ inputTokens: result.usage.inputTokens,
58063
+ outputTokens: result.usage.outputTokens,
58064
+ model: result.model,
58065
+ runtimeApi: true
58066
+ });
58067
+ return { ...result, sessionId: updatedSession.id, mode: updatedSession.mode };
58068
+ } catch (error) {
58069
+ this.eventLog.record("turn.failed", {
58070
+ sessionId: effectiveSession.id,
58071
+ error: error instanceof Error ? error.message : String(error),
58072
+ runtimeApi: true
58073
+ });
58074
+ throw error;
58075
+ }
58076
+ }
58077
+ async *streamTurn(input) {
58078
+ const provider = this.provider;
58079
+ if (!provider) {
58080
+ throw new Error("Runtime provider is not initialized.");
58081
+ }
58082
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
58083
+ if (!session) {
58084
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
58085
+ }
58086
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
58087
+ const messages = [
58088
+ ...effectiveSession.messages,
58089
+ {
58090
+ role: "user",
58091
+ content: input.content
58092
+ }
58093
+ ];
58094
+ this.eventLog.record("turn.started", {
58095
+ sessionId: effectiveSession.id,
58096
+ provider: this.providerType,
58097
+ model: this.getModel(),
58098
+ mode: effectiveSession.mode,
58099
+ streaming: true,
58100
+ runtimeApi: true
58101
+ });
58102
+ let content = "";
58103
+ let completed = false;
58104
+ let failed = false;
58105
+ try {
58106
+ for await (const chunk of provider.stream(messages, {
58107
+ model: input.options?.model,
58108
+ maxTokens: input.options?.maxTokens,
58109
+ temperature: input.options?.temperature,
58110
+ stopSequences: input.options?.stopSequences,
58111
+ system: effectiveSession.instructions ?? input.options?.system,
58112
+ timeout: input.options?.timeout,
58113
+ signal: input.options?.signal,
58114
+ thinking: input.options?.thinking
58115
+ })) {
58116
+ if (chunk.type === "text" && chunk.text) {
58117
+ content += chunk.text;
58118
+ yield {
58119
+ type: "text",
58120
+ sessionId: effectiveSession.id,
58121
+ text: chunk.text
58122
+ };
58123
+ }
58124
+ }
58125
+ const updatedSession = this.runtimeSessionStore.update({
58126
+ ...effectiveSession,
58127
+ messages: [
58128
+ ...effectiveSession.messages,
58129
+ { role: "user", content: input.content },
58130
+ { role: "assistant", content }
58131
+ ]
58132
+ });
58133
+ const result = {
58134
+ sessionId: updatedSession.id,
58135
+ content,
58136
+ usage: {
58137
+ inputTokens: provider.countTokens(input.content),
58138
+ outputTokens: provider.countTokens(content),
58139
+ estimated: true
58140
+ },
58141
+ model: input.options?.model ?? this.getModel(),
58142
+ mode: updatedSession.mode
58143
+ };
58144
+ this.eventLog.record("session.updated", {
58145
+ sessionId: updatedSession.id,
58146
+ messages: updatedSession.messages.length
58147
+ });
58148
+ this.eventLog.record("turn.completed", {
58149
+ sessionId: updatedSession.id,
58150
+ inputTokens: result.usage.inputTokens,
58151
+ outputTokens: result.usage.outputTokens,
58152
+ model: result.model,
58153
+ streaming: true,
58154
+ runtimeApi: true
58155
+ });
58156
+ completed = true;
58157
+ yield { type: "done", sessionId: updatedSession.id, result };
58158
+ } catch (error) {
58159
+ failed = true;
58160
+ const message = error instanceof Error ? error.message : String(error);
58161
+ this.eventLog.record("turn.failed", {
58162
+ sessionId: effectiveSession.id,
58163
+ error: message,
58164
+ streaming: true,
58165
+ runtimeApi: true
58166
+ });
58167
+ yield {
58168
+ type: "error",
58169
+ sessionId: effectiveSession.id,
58170
+ error: message
58171
+ };
58172
+ } finally {
58173
+ if (!completed && !failed) {
58174
+ this.eventLog.record("turn.cancelled", {
58175
+ sessionId: effectiveSession.id,
58176
+ outputTokens: provider.countTokens(content),
58177
+ streaming: true,
58178
+ runtimeApi: true
58179
+ });
58180
+ }
58181
+ }
58182
+ }
58183
+ async executeTool(input) {
58184
+ const startedAt = performance.now();
58185
+ const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
58186
+ if (input.sessionId && !session) {
58187
+ const decision2 = {
58188
+ allowed: false,
58189
+ reason: `Runtime session not found: ${input.sessionId}`,
58190
+ risk: "read-only"
58191
+ };
58192
+ this.eventLog.record("tool.blocked", {
58193
+ sessionId: input.sessionId,
58194
+ mode: input.mode ?? "ask",
58195
+ tool: input.toolName,
58196
+ reason: decision2.reason,
58197
+ runtimeApi: true
58198
+ });
58199
+ return {
58200
+ toolName: input.toolName,
58201
+ success: false,
58202
+ error: decision2.reason,
58203
+ duration: performance.now() - startedAt,
58204
+ decision: decision2
58205
+ };
58206
+ }
58207
+ const mode = input.mode ?? session?.mode ?? "ask";
58208
+ const tool = this.toolRegistry.get(input.toolName);
58209
+ if (!tool) {
58210
+ const decision2 = {
58211
+ allowed: false,
58212
+ reason: "Tool not registered.",
58213
+ risk: "read-only"
58214
+ };
58215
+ this.eventLog.record("tool.blocked", {
58216
+ sessionId: input.sessionId,
58217
+ mode,
58218
+ tool: input.toolName,
58219
+ reason: decision2.reason,
58220
+ runtimeApi: true
58221
+ });
58222
+ return {
58223
+ toolName: input.toolName,
58224
+ success: false,
58225
+ error: decision2.reason,
58226
+ duration: performance.now() - startedAt,
58227
+ decision: decision2
58228
+ };
58229
+ }
58230
+ const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
58231
+ if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
58232
+ const reason = decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
58233
+ this.eventLog.record("tool.blocked", {
58234
+ sessionId: input.sessionId,
58235
+ mode,
58236
+ tool: input.toolName,
58237
+ reason,
58238
+ risk: decision.risk,
58239
+ requiresConfirmation: decision.requiresConfirmation,
58240
+ runtimeApi: true
58241
+ });
58242
+ return {
58243
+ toolName: input.toolName,
58244
+ success: false,
58245
+ error: reason,
58246
+ duration: performance.now() - startedAt,
58247
+ decision
58248
+ };
58249
+ }
58250
+ this.eventLog.record("tool.started", {
58251
+ sessionId: input.sessionId,
58252
+ mode,
58253
+ tool: input.toolName,
58254
+ risk: decision.risk,
58255
+ runtimeApi: true,
58256
+ metadataKeys: Object.keys(input.metadata ?? {}).sort()
58257
+ });
58258
+ const result = await this.toolRegistry.execute(input.toolName, input.input);
58259
+ this.eventLog.record("tool.completed", {
58260
+ sessionId: input.sessionId,
58261
+ mode,
58262
+ tool: input.toolName,
58263
+ success: result.success,
58264
+ duration: result.duration,
58265
+ runtimeApi: true
58266
+ });
58267
+ return {
58268
+ toolName: input.toolName,
58269
+ success: result.success,
58270
+ output: result.data,
58271
+ error: result.error,
58272
+ duration: result.duration,
58273
+ decision
58274
+ };
58275
+ }
58276
+ assertToolAllowed(mode, toolName, input) {
57638
58277
  const tool = this.toolRegistry.get(toolName);
57639
58278
  if (!tool) {
57640
58279
  this.eventLog.record("tool.blocked", {
@@ -57644,7 +58283,7 @@ var AgentRuntime = class {
57644
58283
  });
57645
58284
  return false;
57646
58285
  }
57647
- const decision = this.permissionPolicy.canExecuteTool(mode, tool);
58286
+ const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
57648
58287
  this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
57649
58288
  mode,
57650
58289
  tool: toolName,