@xopcai/xopc 0.0.222 → 0.0.224
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-NItGQmvR.js → activity-store--GBciH10.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DsR_2U9-.js → agent-avatar-dicebear-K7V4XXt7.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BsxTpXyq.js +68 -0
- package/dist/gateway/static/root/assets/{api-53ZXsuyr.js → api-HoIz_ija.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BCzVX09V.js → app-management-settings-panel-xQCmkAHh.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DgSpwqQI.js → appearance-settings-BRoeA4kU.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BXgpBA8w.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-D8o8CP9Y.js → archive-plugin-CteCVsBP.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BQHcAR6J.js → attachment-load-D7xNA2jB.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-CswK3HFb.js → automations-page-BD1vK7r5.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-wrgf-z7D.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BlpyTJ1b.js → binary-plugins-C3DaJa0W.js} +1 -1
- package/dist/gateway/static/root/assets/block-editor-lTkcHTve.js +184 -0
- package/dist/gateway/static/root/assets/browser-settings-page-zhzNkeVG.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-Bi6RSSpD.js → browser-workflow-inputs-1UZ0vnIy.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-CZNOOQY4.js → browser-workflows-page-BHuJOF4M.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DuCmg2Ej.js +7 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-pC2fno7r.js → capability-presets-api-yNqTIuyd.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DjiP3mQQ.js +3 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-B5Szgu_z.js → channel-recipient-api-krezGsKc.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-B4AtvQHk.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-DMxB7slL.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-2fpzufzt.js → chat-terminal-dock-BRrL2iHA.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-fmda2NEP.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-VePLfPUR.js → cron-expression-Bl-2DzBQ.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CJegmPTJ.js → date-picker-CxTl6Wlz.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-B2o9unBk.js → dependency-picker-DSl0mOPa.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-BH4Np-ay.js → desktop-pet-DTeCmCdb.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-Duu3ctxD.js → desktop-pet-settings-BNebxg0V.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BBCUZOg2.js → directory-picker-path-field-Dn9XpmXY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-DaxPZj9e.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DY4Af0fY.js → dist-J_ySZvz0.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DS_o3F97.js → extension-debug-page-D-J-eOTb.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BTLBZdCq.js → extension-page-CpST24nU.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-KTGrYbgk.js → extension-settings-page-4nQXFnFq.js} +1 -1
- package/dist/gateway/static/root/assets/floating-ui.dom-B7uQOZZW.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-D3YJVfzY.js → gateway-config-api-BHWHduDi.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BzTbnu4O.js → gateway-config-swr-yUxMMVjK.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-B8--s3yC.js → gateway-settings-BimMKmkM.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-B2zpkNvi.js → gateway-startup-retry-9mrsL84j.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-MUJ3mEC9.js +1 -0
- package/dist/gateway/static/root/assets/home-page-DSM6aPHF.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-BXRjz-iY.js → image-generation-api-CgFAGDi8.js} +1 -1
- package/dist/gateway/static/root/assets/index-B3zYJBhK.js +74 -0
- package/dist/gateway/static/root/assets/index-D3_xSYKd.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-D-Ib-suu.js → keyboard-shortcuts-settings-6Ar5rfX4.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-tzM0wTL8.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-Bsy1lvAc.js → local-apps-page-B5n-x544.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-iKjqemWG.js → locale-store-CPylQjH9.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CgoQlera.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-D-akydG4.js → management-settings-CXBLyU-0.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DHH4Cu2i.js → markdown-split-CtmQemJi.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-CUsob4Pz.js +69 -0
- package/dist/gateway/static/root/assets/{media-plugins-BwHtUXkj.js → media-plugins-Dsd-IEOW.js} +1 -1
- package/dist/gateway/static/root/assets/messages-B82nsi9k.js +3 -0
- package/dist/gateway/static/root/assets/notes-api-CfKZYrBC.js +1 -0
- package/dist/gateway/static/root/assets/{notes-page-BxM1p6hz.js → notes-page-BKbOTE2n.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-BScELo01.js +4 -0
- package/dist/gateway/static/root/assets/oauth-authorization-window-Cdolr2wE.js +1 -0
- package/dist/gateway/static/root/assets/{popover-select-BzdnTy3h.js → popover-select-CccGri5Y.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-DrfWH1ir.js → product-open-page-DqB9bsDB.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DUoyty8X.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-PeXUdGdO.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-Cx3JxXSL.js → registry-api-B_5D8epF.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-sHho-uXP.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DF7syQRd.js → runtime-tools-settings-panel-DBTH_t0O.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BQ_qRIsM.js → schema-form-CqMKAwV0.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DyvNgaP9.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-CnYf1R7z.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BBHGOQHU.js → settings-form-section-dPriuuYq.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-CiwjP2-b.js → settings-loading-skeleton-B-Mbm8Va.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Rl9waapk.js → settings-page-Dyj3w-Ml.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-C4FxY5J3.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-emEdx7YL.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-BQBVq-sN.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BFoEpQ4I.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-YbtR_zEU.js → skills-page-BNtYnrRT.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-DTmx2Zza.js → skills-page.utils-DjnbNFs5.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BZDJcKdS.js → system-settings-panel-DDStf-jZ.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-ZVwr8KbS.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-BOD2D0dJ.js → theme-store-BN-32Fz5.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-Be9aR9qA.js → use-autosave-C2mKZ-ua.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-CHjIinCW.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-IMc3Ua6C.js → voice-api-key-field-D7OHeQby.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-TC-xQenr.js → work-discovery-overlay-CIiXie7F.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-B2auxcRv.js → workflow-run-setup-panel-9_dAGW3_.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DXpYJxao.js +5 -0
- package/dist/gateway/static/root/index.html +15 -14
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +3 -0
- package/dist/src/agent/agent-manager.d.ts +3 -0
- package/dist/src/agent/agent-manager.js +30 -24
- package/dist/src/agent/embedded/index.d.ts +1 -1
- package/dist/src/agent/embedded/index.js +2 -2
- package/dist/src/agent/embedded/run-for-session.js +101 -62
- package/dist/src/agent/embedded/run-turn.js +56 -28
- package/dist/src/agent/embedded/runs.d.ts +16 -29
- package/dist/src/agent/embedded/runs.js +44 -65
- package/dist/src/agent/embedded/types.d.ts +4 -0
- package/dist/src/agent/orchestration/agent-run-supervisor.d.ts +28 -0
- package/dist/src/agent/orchestration/agent-run-supervisor.js +49 -0
- package/dist/src/agent/orchestration/agent-turn-policy.d.ts +18 -0
- package/dist/src/agent/orchestration/agent-turn-policy.js +36 -0
- package/dist/src/agent/orchestration/llm-turn-retry.d.ts +5 -0
- package/dist/src/agent/orchestration/llm-turn-retry.js +34 -4
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.d.ts +10 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-timeout.js +25 -4
- package/dist/src/agent/service/async-queue.d.ts +16 -3
- package/dist/src/agent/service/async-queue.js +29 -11
- package/dist/src/agent/service/process-direct-streaming.js +27 -4
- package/dist/src/agent/service.js +1 -0
- package/dist/src/agent/tools/exec-command.d.ts +2 -0
- package/dist/src/agent/tools/exec-command.js +70 -7
- package/dist/src/auth/oauth/index.js +3 -3
- package/dist/src/auth/oauth/registry.d.ts +2 -0
- package/dist/src/auth/oauth/registry.js +20 -12
- package/dist/src/auth/oauth/xopc-cloud.d.ts +1 -0
- package/dist/src/auth/oauth/xopc-cloud.js +32 -16
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/tunnel.js +4 -5
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/schema.d.ts +18 -0
- package/dist/src/config/schema.js +19 -1
- package/dist/src/extensions/sdk/index.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/app.js +2 -1
- package/dist/src/gateway/hono/oauth-async.d.ts +1 -0
- package/dist/src/gateway/hono/oauth-async.js +11 -4
- package/dist/src/gateway/hono/routes/config.js +10 -0
- package/dist/src/gateway/hono/routes/host-fs.js +40 -1
- package/dist/src/gateway/hono/routes/media.js +33 -1
- package/dist/src/gateway/hono/routes/notes.js +162 -7
- package/dist/src/gateway/hono/routes/shares.js +141 -6
- package/dist/src/gateway/hono/routes/tunnel.js +47 -10
- package/dist/src/gateway/hono/routes/voice.d.ts +2 -6
- package/dist/src/gateway/hono/routes/voice.js +20 -4
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/run-loop.js +3 -0
- package/dist/src/gateway/server.d.ts +3 -0
- package/dist/src/gateway/server.js +30 -5
- package/dist/src/gateway/service.js +4 -4
- package/dist/src/notes/service.d.ts +6 -2
- package/dist/src/notes/service.js +36 -4
- package/dist/src/providers/index.js +2 -2
- package/dist/src/share/note-share-service.d.ts +67 -0
- package/dist/src/share/note-share-service.js +283 -0
- package/dist/src/share/share-config.js +32 -3
- package/dist/src/share/share-landing.d.ts +5 -1
- package/dist/src/share/share-landing.js +28 -1
- package/dist/src/share/share-store.d.ts +34 -5
- package/dist/src/share/share-store.js +125 -19
- package/dist/src/share/share-thumbnail.js +4 -2
- package/dist/src/share/share-types.d.ts +52 -14
- package/dist/src/share/share-types.js +9 -0
- package/dist/src/share/share-zip.d.ts +2 -2
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/tunnel/env.d.ts +12 -6
- package/dist/src/tunnel/env.js +34 -26
- package/dist/src/tunnel/gateway-lifecycle.js +2 -13
- package/dist/src/tunnel/index.d.ts +1 -1
- package/dist/src/tunnel/index.js +2 -2
- package/dist/src/tunnel/tunnel-audit.d.ts +1 -1
- package/dist/src/tunnel/tunnel-config.d.ts +1 -1
- package/dist/src/tunnel/tunnel-config.js +9 -4
- package/dist/src/tunnel/tunnel-service.d.ts +1 -1
- package/dist/src/tunnel/tunnel-service.js +3 -0
- package/dist/src/tunnel/well-known.d.ts +1 -1
- package/dist/src/tunnel/well-known.js +1 -1
- package/dist/src/tunnel/xopc-cloud-registration.d.ts +9 -0
- package/dist/src/tunnel/xopc-cloud-registration.js +42 -0
- package/dist/src/voice/stt/transcribe-core.js +17 -1
- package/dist/src/voice/stt/types.d.ts +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/agents-DijFbC4G.js +0 -68
- package/dist/gateway/static/root/assets/apps-page-BFAmf9hq.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-B8us5JBf.js +0 -6
- package/dist/gateway/static/root/assets/block-editor-C3mwGsms.js +0 -184
- package/dist/gateway/static/root/assets/browser-settings-page-BeBd17-3.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-Bv0z3KRq.js +0 -7
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BczD-pWE.js +0 -3
- package/dist/gateway/static/root/assets/channels-settings-2KQYq6xl.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-ByRbxC6z.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-PB1boaNy.js +0 -2
- package/dist/gateway/static/root/assets/dist-C230izr8.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-5YQ5BUwp.js +0 -1
- package/dist/gateway/static/root/assets/home-page-DfIVWJl3.js +0 -1
- package/dist/gateway/static/root/assets/index-BXGC3VFm.css +0 -2
- package/dist/gateway/static/root/assets/index-jqDCfet4.js +0 -74
- package/dist/gateway/static/root/assets/local-app-workbench-page-CAb0odzu.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-CFxKbDZl.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-DYkxMtJA.js +0 -69
- package/dist/gateway/static/root/assets/messages-kx5W39dO.js +0 -3
- package/dist/gateway/static/root/assets/notes-api-DJizatxh.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-BGjEC89c.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-Dj9kEQwg.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CBRy5Ezz.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DSwz9RBh.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-WtattyVX.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CNAz_q1F.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CNo4Ajhn.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-B7PI3yZ6.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-DpOH0zWB.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BOf4xCat.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-DrMX5Yhj.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-ewIK2ddC.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Bdn82kFQ.js +0 -5
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/agent/orchestration/agent-run-supervisor.ts
|
|
2
|
+
/** Minimal run-level coordination: root cancellation and per-attempt deadline planning. */
|
|
3
|
+
var AgentRunSupervisor = class {
|
|
4
|
+
deadlineAtMs;
|
|
5
|
+
signal;
|
|
6
|
+
controller = new AbortController();
|
|
7
|
+
timeout;
|
|
8
|
+
forwardParentAbort;
|
|
9
|
+
timeoutMs;
|
|
10
|
+
minimumFallbackMs;
|
|
11
|
+
parentSignal;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.timeoutMs = options.timeoutMs;
|
|
14
|
+
this.minimumFallbackMs = options.minimumFallbackMs ?? 5e3;
|
|
15
|
+
this.deadlineAtMs = options.deadlineAtMs ?? Date.now() + options.timeoutMs;
|
|
16
|
+
this.parentSignal = options.parentSignal;
|
|
17
|
+
this.signal = this.controller.signal;
|
|
18
|
+
this.forwardParentAbort = () => this.controller.abort(this.parentSignal?.reason);
|
|
19
|
+
if (this.parentSignal?.aborted) this.forwardParentAbort();
|
|
20
|
+
else this.parentSignal?.addEventListener("abort", this.forwardParentAbort, { once: true });
|
|
21
|
+
this.timeout = setTimeout(() => this.controller.abort(/* @__PURE__ */ new Error("Agent run deadline expired")), Math.max(0, this.deadlineAtMs - Date.now()));
|
|
22
|
+
}
|
|
23
|
+
planModelAttempt(isFallback) {
|
|
24
|
+
if (this.signal.aborted) return {
|
|
25
|
+
ok: false,
|
|
26
|
+
reason: "Agent run aborted"
|
|
27
|
+
};
|
|
28
|
+
const remainingMs = this.deadlineAtMs - Date.now();
|
|
29
|
+
if (remainingMs <= 0) return {
|
|
30
|
+
ok: false,
|
|
31
|
+
reason: "Agent run deadline expired before the next model attempt"
|
|
32
|
+
};
|
|
33
|
+
if (isFallback && remainingMs < this.minimumFallbackMs) return {
|
|
34
|
+
ok: false,
|
|
35
|
+
reason: "Agent run deadline left too little time for a fallback model attempt"
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
ok: true,
|
|
39
|
+
remainingMs,
|
|
40
|
+
timeoutMs: Math.max(1, Math.min(this.timeoutMs, remainingMs))
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
dispose() {
|
|
44
|
+
clearTimeout(this.timeout);
|
|
45
|
+
this.parentSignal?.removeEventListener("abort", this.forwardParentAbort);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { AgentRunSupervisor };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AfterToolCallContext, BeforeToolCallContext, BeforeToolCallResult, ShouldStopAfterTurnContext } from '@earendil-works/pi-agent-core';
|
|
2
|
+
export interface AgentTurnPolicy {
|
|
3
|
+
reset(): void;
|
|
4
|
+
beforeToolCall(context: BeforeToolCallContext, signal?: AbortSignal): Promise<BeforeToolCallResult | undefined>;
|
|
5
|
+
afterToolCall(context: AfterToolCallContext): Promise<undefined>;
|
|
6
|
+
shouldStopAfterTurn(context: ShouldStopAfterTurnContext): boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface AgentTurnPolicyOptions {
|
|
9
|
+
maxTurns?: number;
|
|
10
|
+
maxToolFailures?: number;
|
|
11
|
+
resolveToolLimit?: (toolName: string, args: unknown) => {
|
|
12
|
+
id: string;
|
|
13
|
+
maxCalls: number;
|
|
14
|
+
} | undefined;
|
|
15
|
+
authorizeToolCall?: (context: BeforeToolCallContext, signal?: AbortSignal) => Promise<BeforeToolCallResult | undefined>;
|
|
16
|
+
}
|
|
17
|
+
/** One user-visible run policy. A fresh instance is created for every embedded run. */
|
|
18
|
+
export declare function createAgentTurnPolicy(options: AgentTurnPolicyOptions): AgentTurnPolicy;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/agent/orchestration/agent-turn-policy.ts
|
|
2
|
+
function assistantMessageCount(messages) {
|
|
3
|
+
return messages.filter((message) => message.role === "assistant").length;
|
|
4
|
+
}
|
|
5
|
+
/** One user-visible run policy. A fresh instance is created for every embedded run. */
|
|
6
|
+
function createAgentTurnPolicy(options) {
|
|
7
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
8
|
+
let toolFailures = 0;
|
|
9
|
+
return {
|
|
10
|
+
reset() {
|
|
11
|
+
toolCalls.clear();
|
|
12
|
+
toolFailures = 0;
|
|
13
|
+
},
|
|
14
|
+
async beforeToolCall(context, signal) {
|
|
15
|
+
const limit = options.resolveToolLimit?.(context.toolCall.name, context.args);
|
|
16
|
+
if (limit) {
|
|
17
|
+
const count = (toolCalls.get(limit.id) ?? 0) + 1;
|
|
18
|
+
toolCalls.set(limit.id, count);
|
|
19
|
+
if (count > limit.maxCalls) return {
|
|
20
|
+
block: true,
|
|
21
|
+
terminate: true,
|
|
22
|
+
reason: `${limit.id} exceeded its per-turn call limit.`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return options.authorizeToolCall?.(context, signal);
|
|
26
|
+
},
|
|
27
|
+
async afterToolCall(context) {
|
|
28
|
+
if (context.isError) toolFailures += 1;
|
|
29
|
+
},
|
|
30
|
+
shouldStopAfterTurn(context) {
|
|
31
|
+
return Boolean(options.maxTurns && assistantMessageCount(context.newMessages) >= options.maxTurns || options.maxToolFailures && toolFailures >= options.maxToolFailures);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { createAgentTurnPolicy };
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { Agent, AgentMessage } from '@earendil-works/pi-agent-core';
|
|
8
8
|
export declare function isTransientLlmErrorMessage(message: string): boolean;
|
|
9
|
+
export type LlmFailureKind = 'transient_network' | 'context_overflow' | 'aborted' | 'permanent';
|
|
10
|
+
export declare function classifyLlmFailure(message: string): LlmFailureKind;
|
|
9
11
|
export declare function getLastAssistantMessage(messages: AgentMessage[]): AgentMessage | undefined;
|
|
10
12
|
/** Raw provider/LLM error from the last failed assistant message, if any. */
|
|
11
13
|
export declare function getAssistantTurnErrorMessage(agent: Agent): string | undefined;
|
|
@@ -20,6 +22,9 @@ export declare function stripTrailingErrorAssistantMessages(messages: AgentMessa
|
|
|
20
22
|
export interface RetryTransientTurnOptions {
|
|
21
23
|
/** Extra turns after a failed assistant message (default 2). */
|
|
22
24
|
maxContinues?: number;
|
|
25
|
+
/** Initial deterministic backoff. Each later retry doubles it. */
|
|
26
|
+
baseDelayMs?: number;
|
|
27
|
+
signal?: AbortSignal;
|
|
23
28
|
sessionKey: string;
|
|
24
29
|
log: {
|
|
25
30
|
warn: (obj: Record<string, unknown>, msg: string) => void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isContextOverflowError } from "./context-overflow.js";
|
|
1
2
|
//#region src/agent/orchestration/llm-turn-retry.ts
|
|
2
3
|
const TRANSIENT_LLM_ERROR_SUBSTRINGS = [
|
|
3
4
|
"fetch failed",
|
|
@@ -16,6 +17,13 @@ function isTransientLlmErrorMessage(message) {
|
|
|
16
17
|
const lower = message.toLowerCase();
|
|
17
18
|
return TRANSIENT_LLM_ERROR_SUBSTRINGS.some((s) => lower.includes(s));
|
|
18
19
|
}
|
|
20
|
+
function classifyLlmFailure(message) {
|
|
21
|
+
const normalized = message.trim().toLowerCase();
|
|
22
|
+
if (normalized === "aborted" || normalized.includes("aborterror")) return "aborted";
|
|
23
|
+
if (isContextOverflowError(message)) return "context_overflow";
|
|
24
|
+
if (isTransientLlmErrorMessage(message)) return "transient_network";
|
|
25
|
+
return "permanent";
|
|
26
|
+
}
|
|
19
27
|
function getLastAssistantMessage(messages) {
|
|
20
28
|
for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "assistant") return messages[i];
|
|
21
29
|
}
|
|
@@ -56,32 +64,54 @@ function stripTrailingErrorAssistantMessages(messages) {
|
|
|
56
64
|
}
|
|
57
65
|
return out;
|
|
58
66
|
}
|
|
67
|
+
async function waitForRetryDelay(delayMs, signal) {
|
|
68
|
+
signal?.throwIfAborted();
|
|
69
|
+
if (delayMs <= 0) return;
|
|
70
|
+
await new Promise((resolve, reject) => {
|
|
71
|
+
const onAbort = () => {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
reject(signal?.reason ?? new DOMException("Aborted", "AbortError"));
|
|
74
|
+
};
|
|
75
|
+
const timer = setTimeout(() => {
|
|
76
|
+
signal?.removeEventListener("abort", onAbort);
|
|
77
|
+
resolve();
|
|
78
|
+
}, delayMs);
|
|
79
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
80
|
+
});
|
|
81
|
+
}
|
|
59
82
|
/**
|
|
60
83
|
* After waitForIdle(), call this to optionally re-run the last user turn when the
|
|
61
84
|
* assistant message only contains a transient provider/network error.
|
|
62
85
|
*/
|
|
63
86
|
async function maybeRetryTurnAfterTransientLlmFailure(agent, options) {
|
|
64
87
|
const maxContinues = options.maxContinues ?? 2;
|
|
88
|
+
const baseDelayMs = Math.max(0, options.baseDelayMs ?? 300);
|
|
65
89
|
let continues = 0;
|
|
66
90
|
while (continues < maxContinues) {
|
|
67
91
|
const last = getLastAssistantMessage(agent.state.messages);
|
|
68
92
|
if (!last) return;
|
|
69
93
|
if (last.stopReason !== "error") return;
|
|
70
94
|
const errMsg = String(last.errorMessage || "");
|
|
71
|
-
|
|
95
|
+
const failureKind = classifyLlmFailure(errMsg);
|
|
96
|
+
if (failureKind !== "transient_network") {
|
|
72
97
|
options.log.warn({
|
|
73
98
|
sessionKey: options.sessionKey,
|
|
74
|
-
errorMessage: errMsg
|
|
99
|
+
errorMessage: errMsg,
|
|
100
|
+
failureKind
|
|
75
101
|
}, "Assistant turn ended with error (not retrying as transient)");
|
|
76
102
|
return;
|
|
77
103
|
}
|
|
78
104
|
continues += 1;
|
|
105
|
+
const retryDelayMs = baseDelayMs * 2 ** (continues - 1);
|
|
79
106
|
options.log.warn({
|
|
80
107
|
sessionKey: options.sessionKey,
|
|
81
108
|
errorMessage: errMsg,
|
|
109
|
+
failureKind,
|
|
82
110
|
continueAttempt: continues,
|
|
83
|
-
maxContinues
|
|
111
|
+
maxContinues,
|
|
112
|
+
retryDelayMs
|
|
84
113
|
}, "LLM request failed with a transient network error; retrying the same turn. If this persists, check outbound HTTPS to the provider API and HTTP(S)_PROXY.");
|
|
114
|
+
await waitForRetryDelay(retryDelayMs, options.signal);
|
|
85
115
|
const trimmed = stripTrailingErrorAssistantMessages(agent.state.messages);
|
|
86
116
|
agent.state.messages = trimmed;
|
|
87
117
|
await agent.continue();
|
|
@@ -89,4 +119,4 @@ async function maybeRetryTurnAfterTransientLlmFailure(agent, options) {
|
|
|
89
119
|
}
|
|
90
120
|
}
|
|
91
121
|
//#endregion
|
|
92
|
-
export { getAssistantTurnErrorMessage, getLastAssistantMessage, isAssistantTurnAborted, isAssistantTurnFailed, isTransientLlmErrorMessage, maybeRetryTurnAfterTransientLlmFailure, stripTrailingErrorAssistantMessages };
|
|
122
|
+
export { classifyLlmFailure, getAssistantTurnErrorMessage, getLastAssistantMessage, isAssistantTurnAborted, isAssistantTurnFailed, isTransientLlmErrorMessage, maybeRetryTurnAfterTransientLlmFailure, stripTrailingErrorAssistantMessages };
|
|
@@ -10,6 +10,15 @@ export declare const MIN_AGENT_TURN_TIMEOUT_MS = 60000;
|
|
|
10
10
|
export declare const MAX_AGENT_TURN_TIMEOUT_MS: number;
|
|
11
11
|
/** Default per-turn timeout (30 minutes). */
|
|
12
12
|
export declare const DEFAULT_AGENT_TURN_TIMEOUT_MS: number;
|
|
13
|
+
export declare const DEFAULT_AGENT_ABORT_GRACE_MS = 5000;
|
|
14
|
+
export declare class AgentTurnUnsettledError extends Error {
|
|
15
|
+
readonly timeoutMs: number;
|
|
16
|
+
readonly abortGraceMs: number;
|
|
17
|
+
constructor(timeoutMs: number, abortGraceMs: number);
|
|
18
|
+
}
|
|
19
|
+
export declare function isAgentTurnUnsettledError(err: unknown): err is AgentTurnUnsettledError;
|
|
13
20
|
export declare function resolveAgentTurnTimeoutMs(config?: Config, sessionKey?: string): number;
|
|
14
21
|
export declare function isAgentTurnTimeoutError(err: unknown): boolean;
|
|
15
|
-
export declare function runAgentTurnWithTimeout(agent: Agent, runTurn: () => Promise<void>, timeoutMs: number
|
|
22
|
+
export declare function runAgentTurnWithTimeout(agent: Agent, runTurn: () => Promise<void>, timeoutMs: number, options?: {
|
|
23
|
+
abortGraceMs?: number;
|
|
24
|
+
}): Promise<void>;
|
|
@@ -6,6 +6,18 @@ const MIN_AGENT_TURN_TIMEOUT_MS = 6e4;
|
|
|
6
6
|
const MAX_AGENT_TURN_TIMEOUT_MS = 14400 * 1e3;
|
|
7
7
|
/** Default per-turn timeout (30 minutes). */
|
|
8
8
|
const DEFAULT_AGENT_TURN_TIMEOUT_MS = 1800 * 1e3;
|
|
9
|
+
const DEFAULT_AGENT_ABORT_GRACE_MS = 5e3;
|
|
10
|
+
var AgentTurnUnsettledError = class extends Error {
|
|
11
|
+
constructor(timeoutMs, abortGraceMs) {
|
|
12
|
+
super(`Agent turn timed out after ${timeoutMs / 1e3}s and did not settle within ${abortGraceMs / 1e3}s`);
|
|
13
|
+
this.timeoutMs = timeoutMs;
|
|
14
|
+
this.abortGraceMs = abortGraceMs;
|
|
15
|
+
this.name = "AgentTurnUnsettledError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function isAgentTurnUnsettledError(err) {
|
|
19
|
+
return err instanceof AgentTurnUnsettledError;
|
|
20
|
+
}
|
|
9
21
|
function resolveAgentTurnTimeoutMs(config, sessionKey) {
|
|
10
22
|
if (!config) return DEFAULT_AGENT_TURN_TIMEOUT_MS;
|
|
11
23
|
const configured = resolveEffectiveAgentManifestForSession(config, sessionKey).runtime?.timeoutMs;
|
|
@@ -15,22 +27,31 @@ function resolveAgentTurnTimeoutMs(config, sessionKey) {
|
|
|
15
27
|
function isAgentTurnTimeoutError(err) {
|
|
16
28
|
return err instanceof Error && err.message.startsWith("Agent turn timed out after");
|
|
17
29
|
}
|
|
18
|
-
async function runAgentTurnWithTimeout(agent, runTurn, timeoutMs) {
|
|
30
|
+
async function runAgentTurnWithTimeout(agent, runTurn, timeoutMs, options = {}) {
|
|
19
31
|
let timeoutId;
|
|
20
32
|
const timeoutPromise = new Promise((_, reject) => {
|
|
21
33
|
timeoutId = setTimeout(() => reject(/* @__PURE__ */ new Error(`Agent turn timed out after ${timeoutMs / 1e3}s`)), timeoutMs);
|
|
22
34
|
});
|
|
35
|
+
const runTurnPromise = Promise.resolve().then(runTurn);
|
|
23
36
|
try {
|
|
24
|
-
await Promise.race([
|
|
37
|
+
await Promise.race([runTurnPromise.finally(() => {
|
|
25
38
|
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
26
39
|
}), timeoutPromise]);
|
|
27
40
|
} catch (err) {
|
|
28
41
|
if (isAgentTurnTimeoutError(err)) {
|
|
29
42
|
agent.abort();
|
|
30
|
-
|
|
43
|
+
const abortGraceMs = options.abortGraceMs ?? 5e3;
|
|
44
|
+
let graceTimer;
|
|
45
|
+
try {
|
|
46
|
+
await Promise.race([Promise.allSettled([runTurnPromise, agent.waitForIdle()]), new Promise((_, reject) => {
|
|
47
|
+
graceTimer = setTimeout(() => reject(new AgentTurnUnsettledError(timeoutMs, abortGraceMs)), abortGraceMs);
|
|
48
|
+
})]);
|
|
49
|
+
} finally {
|
|
50
|
+
if (graceTimer !== void 0) clearTimeout(graceTimer);
|
|
51
|
+
}
|
|
31
52
|
}
|
|
32
53
|
throw err;
|
|
33
54
|
}
|
|
34
55
|
}
|
|
35
56
|
//#endregion
|
|
36
|
-
export { DEFAULT_AGENT_TURN_TIMEOUT_MS, MAX_AGENT_TURN_TIMEOUT_MS, MIN_AGENT_TURN_TIMEOUT_MS, isAgentTurnTimeoutError, resolveAgentTurnTimeoutMs, runAgentTurnWithTimeout };
|
|
57
|
+
export { AgentTurnUnsettledError, DEFAULT_AGENT_ABORT_GRACE_MS, DEFAULT_AGENT_TURN_TIMEOUT_MS, MAX_AGENT_TURN_TIMEOUT_MS, MIN_AGENT_TURN_TIMEOUT_MS, isAgentTurnTimeoutError, isAgentTurnUnsettledError, resolveAgentTurnTimeoutMs, runAgentTurnWithTimeout };
|
|
@@ -3,15 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Replaces the ad-hoc `eventQueue + resolveWaiting` single-slot pattern that
|
|
5
5
|
* the streaming direct turn used to manage run events. The previous pattern was
|
|
6
|
-
* lossy if two pushes landed before the single waiter resumed; this queue
|
|
7
|
-
*
|
|
6
|
+
* lossy if two pushes landed before the single waiter resumed; this queue buffers
|
|
7
|
+
* until consumed, supports an explicit bound, and drains cleanly on close.
|
|
8
8
|
*/
|
|
9
|
+
export interface AsyncQueueOptions<T> {
|
|
10
|
+
/** Maximum buffer size. Lossy events are evicted; critical-only overflow fails fast. */
|
|
11
|
+
maxBuffered?: number;
|
|
12
|
+
isDroppable?: (value: T) => boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare class AsyncQueueOverflowError extends Error {
|
|
15
|
+
readonly maxBuffered: number;
|
|
16
|
+
constructor(maxBuffered: number);
|
|
17
|
+
}
|
|
9
18
|
export declare class AsyncQueue<T> implements AsyncIterable<T> {
|
|
19
|
+
private readonly options;
|
|
10
20
|
private readonly buffer;
|
|
11
21
|
private readonly waiters;
|
|
12
22
|
private closed;
|
|
23
|
+
private dropped;
|
|
24
|
+
constructor(options?: AsyncQueueOptions<T>);
|
|
13
25
|
/** Push a value to the queue. No-op when the queue is closed. */
|
|
14
|
-
push(value: T):
|
|
26
|
+
push(value: T): boolean;
|
|
27
|
+
get droppedCount(): number;
|
|
15
28
|
/** Close the queue. Pending iterators drain any buffered values and then complete. */
|
|
16
29
|
close(): void;
|
|
17
30
|
/** True if the queue is closed and the internal buffer is drained. */
|
|
@@ -1,25 +1,43 @@
|
|
|
1
1
|
//#region src/agent/service/async-queue.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*/
|
|
2
|
+
var AsyncQueueOverflowError = class extends Error {
|
|
3
|
+
constructor(maxBuffered) {
|
|
4
|
+
super(`Async queue exceeded its ${maxBuffered}-event buffer`);
|
|
5
|
+
this.maxBuffered = maxBuffered;
|
|
6
|
+
this.name = "AsyncQueueOverflowError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
10
9
|
var AsyncQueue = class {
|
|
11
10
|
buffer = [];
|
|
12
11
|
waiters = [];
|
|
13
12
|
closed = false;
|
|
13
|
+
dropped = 0;
|
|
14
|
+
constructor(options = {}) {
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
14
17
|
/** Push a value to the queue. No-op when the queue is closed. */
|
|
15
18
|
push(value) {
|
|
16
|
-
if (this.closed) return;
|
|
19
|
+
if (this.closed) return false;
|
|
17
20
|
const waiter = this.waiters.shift();
|
|
18
21
|
if (waiter) {
|
|
19
22
|
waiter(value);
|
|
20
|
-
return;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
const maxBuffered = this.options.maxBuffered;
|
|
26
|
+
if (maxBuffered && this.buffer.length >= maxBuffered) {
|
|
27
|
+
const droppableIndex = this.options.isDroppable ? this.buffer.findIndex(this.options.isDroppable) : -1;
|
|
28
|
+
if (droppableIndex >= 0) {
|
|
29
|
+
this.buffer.splice(droppableIndex, 1);
|
|
30
|
+
this.dropped += 1;
|
|
31
|
+
} else if (this.options.isDroppable?.(value)) {
|
|
32
|
+
this.dropped += 1;
|
|
33
|
+
return false;
|
|
34
|
+
} else throw new AsyncQueueOverflowError(maxBuffered);
|
|
21
35
|
}
|
|
22
36
|
this.buffer.push(value);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
get droppedCount() {
|
|
40
|
+
return this.dropped;
|
|
23
41
|
}
|
|
24
42
|
/** Close the queue. Pending iterators drain any buffered values and then complete. */
|
|
25
43
|
close() {
|
|
@@ -48,4 +66,4 @@ var AsyncQueue = class {
|
|
|
48
66
|
};
|
|
49
67
|
const CLOSE_SENTINEL = Symbol("AsyncQueue.close");
|
|
50
68
|
//#endregion
|
|
51
|
-
export { AsyncQueue };
|
|
69
|
+
export { AsyncQueue, AsyncQueueOverflowError };
|
|
@@ -11,9 +11,16 @@ import { isVoiceLikeAttachment, mergeVoiceTranscriptsIntoUserText } from "../../
|
|
|
11
11
|
import { applyReasoningVisibility } from "../streaming/reasoning-visibility.js";
|
|
12
12
|
import { isSessionSourceBinding, summarizeSourceContext } from "../source-context/types.js";
|
|
13
13
|
import { injectSourceContextsIntoUserMessage } from "../source-context/injector.js";
|
|
14
|
-
import { AsyncQueue } from "./async-queue.js";
|
|
14
|
+
import { AsyncQueue, AsyncQueueOverflowError } from "./async-queue.js";
|
|
15
15
|
import { hydratePerTurnState, runDirectAgentTurn, tryRunSlashCommand } from "./direct-turn-helpers.js";
|
|
16
16
|
//#region src/agent/service/process-direct-streaming.ts
|
|
17
|
+
const MAX_BUFFERED_STREAM_EVENTS = 512;
|
|
18
|
+
const LOSSY_STREAM_EVENT_TYPES = new Set([
|
|
19
|
+
"message_update",
|
|
20
|
+
"tool_execution_update",
|
|
21
|
+
"progress",
|
|
22
|
+
"review_delta"
|
|
23
|
+
]);
|
|
17
24
|
function isReviewOutput(value) {
|
|
18
25
|
return !!value && typeof value === "object" && !Array.isArray(value) && value.type === "review";
|
|
19
26
|
}
|
|
@@ -118,7 +125,10 @@ async function* runProcessDirectStreaming(deps, input) {
|
|
|
118
125
|
const sessionKey = input.sessionKey ?? "agent:main:main";
|
|
119
126
|
const { channel, chatId } = await deps.resolveSessionEndpoint(sessionKey);
|
|
120
127
|
const context = deps.initDirectStreamingSession(sessionKey, channel, chatId, input.origin);
|
|
121
|
-
const queue = new AsyncQueue(
|
|
128
|
+
const queue = new AsyncQueue({
|
|
129
|
+
maxBuffered: MAX_BUFFERED_STREAM_EVENTS,
|
|
130
|
+
isDroppable: (event) => LOSSY_STREAM_EVENT_TYPES.has(event.type)
|
|
131
|
+
});
|
|
122
132
|
let reasoningLevel = channel === "webchat" ? resolveConfiguredActivityDetailDefault(deps.getConfig()) : "stream";
|
|
123
133
|
const pushVisible = (event) => {
|
|
124
134
|
const visible = channel === "webchat" ? event : applyReasoningVisibility(event, reasoningLevel);
|
|
@@ -144,6 +154,7 @@ async function* runProcessDirectStreaming(deps, input) {
|
|
|
144
154
|
let ranSlashCommand = false;
|
|
145
155
|
let mergedUserText = input.content;
|
|
146
156
|
let webchatSlashReceipt;
|
|
157
|
+
let streamOverflowed = false;
|
|
147
158
|
let slashCommandMetadata;
|
|
148
159
|
const slashTraceRows = [];
|
|
149
160
|
const taskPromise = (async () => {
|
|
@@ -301,12 +312,24 @@ async function* runProcessDirectStreaming(deps, input) {
|
|
|
301
312
|
clearPendingTranscriptUserMessage(sessionKey, pendingUserMessage);
|
|
302
313
|
}
|
|
303
314
|
} catch (err) {
|
|
304
|
-
if (
|
|
315
|
+
if (err instanceof AsyncQueueOverflowError) {
|
|
316
|
+
streamOverflowed = true;
|
|
317
|
+
await abortEmbeddedRun(sessionKey).catch(() => false);
|
|
318
|
+
deps.log.warn({
|
|
319
|
+
err,
|
|
320
|
+
sessionKey,
|
|
321
|
+
maxBuffered: err.maxBuffered
|
|
322
|
+
}, "Aborted agent stream because the consumer could not keep up with critical events");
|
|
323
|
+
} else if (!abortHandled) pushVisible({
|
|
305
324
|
type: "error",
|
|
306
325
|
content: formatStreamError(err instanceof Error ? err.message : String(err))
|
|
307
326
|
});
|
|
308
327
|
} finally {
|
|
309
|
-
if (
|
|
328
|
+
if (queue.droppedCount > 0) deps.log.warn({
|
|
329
|
+
sessionKey,
|
|
330
|
+
droppedEvents: queue.droppedCount
|
|
331
|
+
}, "Coalesced stream progress events because the consumer fell behind");
|
|
332
|
+
if (!userAborted && !streamOverflowed && channel === "webchat") try {
|
|
310
333
|
const ttsAudioEvent = await deps.maybeEmitWebchatTts(sessionKey, inboundVoice);
|
|
311
334
|
if (ttsAudioEvent) queue.push(ttsAudioEvent);
|
|
312
335
|
} catch (ttsErr) {
|
|
@@ -602,6 +602,7 @@ var AgentService = class {
|
|
|
602
602
|
workspaceDir,
|
|
603
603
|
transcriptRuntime: params.transcriptRuntime,
|
|
604
604
|
timeoutMs: resolveAgentTurnTimeoutMs(this.effectiveAppConfig(), params.parentSessionKey),
|
|
605
|
+
turnPolicy: this.agentManager.createAgentTurnPolicy(params.parentSessionKey),
|
|
605
606
|
abortSignal: params.abortSignal,
|
|
606
607
|
onEvent: params.onEvent
|
|
607
608
|
}));
|
|
@@ -25,6 +25,45 @@ function commandStatus(exitCode, timedOut) {
|
|
|
25
25
|
if (exitCode === 0) return "success";
|
|
26
26
|
return "failed";
|
|
27
27
|
}
|
|
28
|
+
function appendBoundedTail(current, chunk, maxChars) {
|
|
29
|
+
const combined = current + chunk;
|
|
30
|
+
if (combined.length <= maxChars) return {
|
|
31
|
+
value: combined,
|
|
32
|
+
truncated: false
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
value: combined.slice(-maxChars),
|
|
36
|
+
truncated: true
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function terminateProcessTree(proc) {
|
|
40
|
+
if (!proc.pid) return;
|
|
41
|
+
if (process.platform === "win32") {
|
|
42
|
+
const killer = spawn("taskkill", [
|
|
43
|
+
"/pid",
|
|
44
|
+
String(proc.pid),
|
|
45
|
+
"/t",
|
|
46
|
+
"/f"
|
|
47
|
+
], {
|
|
48
|
+
stdio: "ignore",
|
|
49
|
+
windowsHide: true
|
|
50
|
+
});
|
|
51
|
+
killer.once("error", () => {
|
|
52
|
+
try {
|
|
53
|
+
proc.kill("SIGKILL");
|
|
54
|
+
} catch {}
|
|
55
|
+
});
|
|
56
|
+
killer.unref();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
process.kill(-proc.pid, "SIGKILL");
|
|
61
|
+
return;
|
|
62
|
+
} catch {}
|
|
63
|
+
try {
|
|
64
|
+
proc.kill("SIGKILL");
|
|
65
|
+
} catch {}
|
|
66
|
+
}
|
|
28
67
|
function commandFailureHint(details) {
|
|
29
68
|
if (details.status === "success") return void 0;
|
|
30
69
|
if (details.status === "timed_out") return "The command timed out. Re-run a narrower command, increase timeoutMs if the long run is expected, or inspect partial output before retrying.";
|
|
@@ -36,6 +75,7 @@ function formatOutputForModel(details, maxOutputChars) {
|
|
|
36
75
|
let prefix = "";
|
|
37
76
|
if (details.timedOut) prefix += `Command timed out after ${Math.round(details.durationMs / 1e3)}s\n`;
|
|
38
77
|
if (details.exitCode !== 0 && details.exitCode != null) prefix += `Command exited with code ${details.exitCode}\n`;
|
|
78
|
+
if (details.captureTruncated) prefix += `Earlier command output was discarded after ${formatSize(details.totalOutputBytes)}; showing the latest captured output.\n`;
|
|
39
79
|
const truncation = truncateTail(details.aggregatedOutput, { maxBytes: Math.min(maxOutputChars, DEFAULT_MAX_OUTPUT_CHARS) });
|
|
40
80
|
let text = `${prefix}${truncation.content}`.trimEnd();
|
|
41
81
|
if (!text) text = "(no output)";
|
|
@@ -78,6 +118,8 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
78
118
|
timedOut: false,
|
|
79
119
|
truncated: false,
|
|
80
120
|
outputBytes: 0,
|
|
121
|
+
totalOutputBytes: 0,
|
|
122
|
+
captureTruncated: false,
|
|
81
123
|
stdout: "",
|
|
82
124
|
stderr: "cmd is required",
|
|
83
125
|
aggregatedOutput: "cmd is required",
|
|
@@ -106,6 +148,8 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
106
148
|
timedOut: false,
|
|
107
149
|
truncated: false,
|
|
108
150
|
outputBytes: Buffer.byteLength(text),
|
|
151
|
+
totalOutputBytes: Buffer.byteLength(text),
|
|
152
|
+
captureTruncated: false,
|
|
109
153
|
stdout: "",
|
|
110
154
|
stderr: text,
|
|
111
155
|
aggregatedOutput: text,
|
|
@@ -120,11 +164,14 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
120
164
|
let stdout = "";
|
|
121
165
|
let stderr = "";
|
|
122
166
|
let aggregatedOutput = "";
|
|
167
|
+
let totalOutputBytes = 0;
|
|
168
|
+
let captureTruncated = false;
|
|
123
169
|
let timedOut = false;
|
|
124
170
|
let settled = false;
|
|
125
171
|
return new Promise((resolveTool) => {
|
|
126
172
|
const proc = spawn(command, [], {
|
|
127
173
|
shell: true,
|
|
174
|
+
detached: process.platform !== "win32",
|
|
128
175
|
cwd: policy.effectiveCwd,
|
|
129
176
|
env: {
|
|
130
177
|
...runtimeEnv,
|
|
@@ -134,9 +181,19 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
134
181
|
const publishDelta = (stream, raw) => {
|
|
135
182
|
const text = raw.toString();
|
|
136
183
|
if (!text) return;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
184
|
+
totalOutputBytes += Buffer.byteLength(text);
|
|
185
|
+
if (stream === "stdout") {
|
|
186
|
+
const next = appendBoundedTail(stdout, text, maxOutputChars);
|
|
187
|
+
stdout = next.value;
|
|
188
|
+
captureTruncated ||= next.truncated;
|
|
189
|
+
} else {
|
|
190
|
+
const next = appendBoundedTail(stderr, text, maxOutputChars);
|
|
191
|
+
stderr = next.value;
|
|
192
|
+
captureTruncated ||= next.truncated;
|
|
193
|
+
}
|
|
194
|
+
const nextAggregate = appendBoundedTail(aggregatedOutput, text, maxOutputChars);
|
|
195
|
+
aggregatedOutput = nextAggregate.value;
|
|
196
|
+
captureTruncated ||= nextAggregate.truncated;
|
|
140
197
|
const delta = text.length > STREAM_DELTA_MAX_CHARS ? `${text.slice(0, STREAM_DELTA_MAX_CHARS)}\n[stream delta truncated]` : text;
|
|
141
198
|
onUpdate?.({
|
|
142
199
|
content: [],
|
|
@@ -155,8 +212,12 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
155
212
|
clearTimeout(timeout);
|
|
156
213
|
signal?.removeEventListener("abort", abort);
|
|
157
214
|
if (errorText) {
|
|
158
|
-
|
|
159
|
-
|
|
215
|
+
totalOutputBytes += Buffer.byteLength(errorText);
|
|
216
|
+
const nextStderr = appendBoundedTail(stderr, errorText, maxOutputChars);
|
|
217
|
+
stderr = nextStderr.value;
|
|
218
|
+
const nextAggregate = appendBoundedTail(aggregatedOutput, errorText, maxOutputChars);
|
|
219
|
+
aggregatedOutput = nextAggregate.value;
|
|
220
|
+
captureTruncated ||= nextStderr.truncated || nextAggregate.truncated;
|
|
160
221
|
}
|
|
161
222
|
const durationMs = Date.now() - startTime;
|
|
162
223
|
const baseDetails = {
|
|
@@ -168,6 +229,8 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
168
229
|
timedOut,
|
|
169
230
|
truncated: false,
|
|
170
231
|
outputBytes: Buffer.byteLength(aggregatedOutput),
|
|
232
|
+
totalOutputBytes,
|
|
233
|
+
captureTruncated,
|
|
171
234
|
stdout,
|
|
172
235
|
stderr,
|
|
173
236
|
aggregatedOutput
|
|
@@ -190,11 +253,11 @@ function createExecCommandTool(workspaceCwd, options) {
|
|
|
190
253
|
};
|
|
191
254
|
const abort = () => {
|
|
192
255
|
timedOut = true;
|
|
193
|
-
proc
|
|
256
|
+
terminateProcessTree(proc);
|
|
194
257
|
};
|
|
195
258
|
const timeout = setTimeout(() => {
|
|
196
259
|
timedOut = true;
|
|
197
|
-
proc
|
|
260
|
+
terminateProcessTree(proc);
|
|
198
261
|
}, timeoutMs);
|
|
199
262
|
if (signal?.aborted) abort();
|
|
200
263
|
else signal?.addEventListener("abort", abort, { once: true });
|
|
@@ -8,8 +8,8 @@ import { init_kimi_coding, kimiCodingOAuthProvider } from "./kimi-coding.js";
|
|
|
8
8
|
import { init_minimax_cn, minimaxCnOAuthProvider } from "./minimax-cn.js";
|
|
9
9
|
import { init_minimax, minimaxOAuthProvider } from "./minimax.js";
|
|
10
10
|
import { init_openai_codex, loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from "./openai-codex.js";
|
|
11
|
-
import { init_xopc_cloud, xopcCloudOAuthProvider } from "./xopc-cloud.js";
|
|
12
|
-
import { OAUTH_PROVIDER_DEFINITIONS, getOAuthProviderDefinition, getOAuthProviderIds, getOAuthProviderInterfaces, init_registry, isOAuthOnlyProvider } from "./registry.js";
|
|
11
|
+
import { init_xopc_cloud, xopcCloudOAuthProvider, xopcTunnelOAuthProvider } from "./xopc-cloud.js";
|
|
12
|
+
import { OAUTH_PROVIDER_DEFINITIONS, getModelOAuthProviderIds, getOAuthProviderDefinition, getOAuthProviderIds, getOAuthProviderInterfaces, init_registry, isOAuthOnlyProvider } from "./registry.js";
|
|
13
13
|
//#region src/auth/oauth/index.ts
|
|
14
14
|
init_anthropic();
|
|
15
15
|
init_minimax();
|
|
@@ -22,4 +22,4 @@ init_openai_codex();
|
|
|
22
22
|
init_xopc_cloud();
|
|
23
23
|
init_registry();
|
|
24
24
|
//#endregion
|
|
25
|
-
export { OAUTH_PROVIDER_DEFINITIONS, anthropicOAuthProvider, getOAuthProviderDefinition, getOAuthProviderIds, getOAuthProviderInterfaces, githubCopilotOAuthProvider, antigravityOAuthProvider as googleAntigravityOAuthProvider, geminiCliOAuthProvider as googleGeminiCliOAuthProvider, isOAuthOnlyProvider, kimiCodingOAuthProvider, loginAnthropic, loginAntigravity, loginGeminiCli, loginOpenAICodex, minimaxCnOAuthProvider, minimaxOAuthProvider, openaiCodexOAuthProvider, refreshAnthropicToken, refreshAntigravityToken, refreshGoogleCloudToken, refreshOpenAICodexToken, xopcCloudOAuthProvider };
|
|
25
|
+
export { OAUTH_PROVIDER_DEFINITIONS, anthropicOAuthProvider, getModelOAuthProviderIds, getOAuthProviderDefinition, getOAuthProviderIds, getOAuthProviderInterfaces, githubCopilotOAuthProvider, antigravityOAuthProvider as googleAntigravityOAuthProvider, geminiCliOAuthProvider as googleGeminiCliOAuthProvider, isOAuthOnlyProvider, kimiCodingOAuthProvider, loginAnthropic, loginAntigravity, loginGeminiCli, loginOpenAICodex, minimaxCnOAuthProvider, minimaxOAuthProvider, openaiCodexOAuthProvider, refreshAnthropicToken, refreshAntigravityToken, refreshGoogleCloudToken, refreshOpenAICodexToken, xopcCloudOAuthProvider, xopcTunnelOAuthProvider };
|
|
@@ -2,6 +2,7 @@ import type { OAuthProviderInterface } from './types.js';
|
|
|
2
2
|
export interface OAuthProviderDefinition {
|
|
3
3
|
displayName: string;
|
|
4
4
|
oauthOnly?: boolean;
|
|
5
|
+
purpose: 'models' | 'tunnel';
|
|
5
6
|
provider: OAuthProviderInterface;
|
|
6
7
|
profileId: string;
|
|
7
8
|
urlPrompt: string;
|
|
@@ -10,4 +11,5 @@ export declare const OAUTH_PROVIDER_DEFINITIONS: Readonly<Record<string, OAuthPr
|
|
|
10
11
|
export declare function getOAuthProviderDefinition(provider: string): OAuthProviderDefinition | undefined;
|
|
11
12
|
export declare function getOAuthProviderInterfaces(): Record<string, OAuthProviderInterface>;
|
|
12
13
|
export declare function getOAuthProviderIds(): string[];
|
|
14
|
+
export declare function getModelOAuthProviderIds(): string[];
|
|
13
15
|
export declare function isOAuthOnlyProvider(provider: string): boolean;
|