@dotobokuri/fleet-console 1.63.0 → 1.65.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.mjs +386 -82
- package/dist/client/assets/{_baseUniq-CVUU389k.js → _baseUniq-DyzqDsbR.js} +1 -1
- package/dist/client/assets/{arc-Fg3WjPoW.js → arc-D9PB38OE.js} +1 -1
- package/dist/client/assets/{architectureDiagram-Q4EWVU46-gAB_QWIv.js → architectureDiagram-Q4EWVU46-0L3Tlker.js} +1 -1
- package/dist/client/assets/{blockDiagram-DXYQGD6D-DCY_3CSv.js → blockDiagram-DXYQGD6D-BCAdqHmo.js} +1 -1
- package/dist/client/assets/{c4Diagram-AHTNJAMY-2ai4d9rg.js → c4Diagram-AHTNJAMY-oK3f-N6i.js} +1 -1
- package/dist/client/assets/channel-CzEHIBah.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-C-sjgNCE.js → chunk-4BX2VUAB-CIYxtKO7.js} +1 -1
- package/dist/client/assets/{chunk-4TB4RGXK-Co7w9KaD.js → chunk-4TB4RGXK-CKA_-tPR.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-Dspr2174.js → chunk-55IACEB6-ArIbE5m1.js} +1 -1
- package/dist/client/assets/{chunk-EDXVE4YY-UzzG0ax3.js → chunk-EDXVE4YY-bGzMBuDL.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-DKXcUQqJ.js → chunk-FMBD7UC4-CZUkX3ry.js} +1 -1
- package/dist/client/assets/{chunk-OYMX7WX6-vW--qrkP.js → chunk-OYMX7WX6-CNXmIVXX.js} +1 -1
- package/dist/client/assets/{chunk-QZHKN3VN-DyE-yBhf.js → chunk-QZHKN3VN-B3t4h1MD.js} +1 -1
- package/dist/client/assets/{chunk-YZCP3GAM-C7LLTO2-.js → chunk-YZCP3GAM-CdGF0f8H.js} +1 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-jNK4g1rr.js +1 -0
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-jNK4g1rr.js +1 -0
- package/dist/client/assets/clone-DggrGKv8.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-BkDNeJiw.js → cose-bilkent-S5V4N54A-BESjfcni.js} +1 -1
- package/dist/client/assets/{dagre-KV5264BT-DqeN9oF3.js → dagre-KV5264BT-WpQhPw2a.js} +1 -1
- package/dist/client/assets/{diagram-5BDNPKRD-BXzt4-3Y.js → diagram-5BDNPKRD-BfAkutIX.js} +1 -1
- package/dist/client/assets/{diagram-G4DWMVQ6-DbzDYVOf.js → diagram-G4DWMVQ6-C9I16SLL.js} +1 -1
- package/dist/client/assets/{diagram-MMDJMWI5-wPQu3o7B.js → diagram-MMDJMWI5-CVJMM2zJ.js} +1 -1
- package/dist/client/assets/{diagram-TYMM5635-C-vwFwzf.js → diagram-TYMM5635-DTqr7jJ3.js} +1 -1
- package/dist/client/assets/{erDiagram-SMLLAGMA-CcukuTgN.js → erDiagram-SMLLAGMA-B09ElCdB.js} +1 -1
- package/dist/client/assets/{flowDiagram-DWJPFMVM-BT8ZNr2Y.js → flowDiagram-DWJPFMVM-C93jg-t6.js} +1 -1
- package/dist/client/assets/{ganttDiagram-T4ZO3ILL-B_wNcZrL.js → ganttDiagram-T4ZO3ILL-5Js2lpdY.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-UUTBAWPF-dUwwvDSd.js → gitGraphDiagram-UUTBAWPF-BxGzg1Rc.js} +1 -1
- package/dist/client/assets/{graph-C4i_jr7e.js → graph-BkRyh4eN.js} +1 -1
- package/dist/client/assets/index-BSVaW3Ov.js +465 -0
- package/dist/client/assets/index-DxjgOu3C.css +1 -0
- package/dist/client/assets/{infoDiagram-42DDH7IO-Bf2KPu0t.js → infoDiagram-42DDH7IO-DZPp1lR6.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-UXIWVN3A-DjHChg2o.js → ishikawaDiagram-UXIWVN3A-CXTuQ2Bb.js} +1 -1
- package/dist/client/assets/{journeyDiagram-VCZTEJTY-B08epGYF.js → journeyDiagram-VCZTEJTY--u6tYqhF.js} +1 -1
- package/dist/client/assets/{kanban-definition-6JOO6SKY-BFasXRgc.js → kanban-definition-6JOO6SKY-CGMEohiQ.js} +1 -1
- package/dist/client/assets/{layout-Q_W10VzL.js → layout-Bzu8ET7F.js} +1 -1
- package/dist/client/assets/{linear-Dy4fc5kq.js → linear-B6htRUTP.js} +1 -1
- package/dist/client/assets/{mermaid.core-OtTy8N5f.js → mermaid.core-CtpLAI-c.js} +4 -4
- package/dist/client/assets/{min-DODD7JTz.js → min-CEURoL5k.js} +1 -1
- package/dist/client/assets/{mindmap-definition-QFDTVHPH-DMhpsiYD.js → mindmap-definition-QFDTVHPH-B-HiXlEN.js} +1 -1
- package/dist/client/assets/{pieDiagram-DEJITSTG-C5usaVgs.js → pieDiagram-DEJITSTG-DQgiLkTU.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-34T5L4WZ-B-b2NvBz.js → quadrantDiagram-34T5L4WZ-xLh7CKRW.js} +1 -1
- package/dist/client/assets/{requirementDiagram-MS252O5E-D6_4jY3n.js → requirementDiagram-MS252O5E-O1SOxLMB.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-XADWPNL6-B6imEhCV.js → sankeyDiagram-XADWPNL6-D-mh4ZYc.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-FGHM5R23-BRHNnuqK.js → sequenceDiagram-FGHM5R23-Dp2XhLFP.js} +1 -1
- package/dist/client/assets/{stateDiagram-FHFEXIEX-RiIddIHL.js → stateDiagram-FHFEXIEX-UQkaQPQt.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CRw5Ot78.js +1 -0
- package/dist/client/assets/{timeline-definition-GMOUNBTQ-BhP14Blt.js → timeline-definition-GMOUNBTQ-DDMfKpma.js} +1 -1
- package/dist/client/assets/{vennDiagram-DHZGUBPP-CtzwrBNs.js → vennDiagram-DHZGUBPP-DaGxBzx2.js} +1 -1
- package/dist/client/assets/{wardley-RL74JXVD-TXsee18-.js → wardley-RL74JXVD-DBNvUuF6.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-NUSXRM2D-CrJP7pf7.js → wardleyDiagram-NUSXRM2D-IbDED74Y.js} +1 -1
- package/dist/client/assets/{xychartDiagram-5P7HB3ND-rB-PigjI.js → xychartDiagram-5P7HB3ND-0RafK-TZ.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/fleet-plugins/ledger/routes.mjs +130 -1
- package/dist/fleet-plugins/quota/routes.mjs +130 -1
- package/dist/fleet-plugins/scuttlebutt/routes.mjs +376 -68
- package/dist/fleet-plugins/terminal/routes.mjs +727 -155
- package/dist/fleet.mjs +386 -82
- package/package.json +1 -1
- package/dist/client/assets/channel-DlA1BRCV.js +0 -1
- package/dist/client/assets/classDiagram-6PBFFD2Q-rBpGSdtk.js +0 -1
- package/dist/client/assets/classDiagram-v2-HSJHXN6E-rBpGSdtk.js +0 -1
- package/dist/client/assets/clone-_1aYWCbr.js +0 -1
- package/dist/client/assets/index-BXtDpU36.js +0 -465
- package/dist/client/assets/index-CLb_APbh.css +0 -1
- package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-CsHfIgMa.js +0 -1
|
@@ -20839,7 +20839,7 @@ var models_default = {
|
|
|
20839
20839
|
codex: {
|
|
20840
20840
|
name: "Codex",
|
|
20841
20841
|
defaultModel: "gpt-5.6-sol",
|
|
20842
|
-
source: "codex app-server model/list (codex-cli 0.147.0, observed 2026-08-11) for model/effort/service-tier; Fleet catalog effort ladders are capped at max because harness launch capabilities are not model rungs;
|
|
20842
|
+
source: "codex app-server model/list (codex-cli 0.147.0, observed 2026-08-11) for model/effort/service-tier and the unsuffixed 272000 defaults; Fleet catalog effort ladders are capped at max because harness launch capabilities are not model rungs; 2026-08-17 production Codex live observations added explicit 1M (1000000) variants on the same upstream bases",
|
|
20843
20843
|
models: [
|
|
20844
20844
|
{
|
|
20845
20845
|
modelId: "gpt-5.6-sol",
|
|
@@ -20966,6 +20966,135 @@ var models_default = {
|
|
|
20966
20966
|
"gpt-5.6-luna-fast"
|
|
20967
20967
|
],
|
|
20968
20968
|
benchmarkKey: "gpt-5.6-luna"
|
|
20969
|
+
},
|
|
20970
|
+
{
|
|
20971
|
+
modelId: "gpt-5.6-sol-1m",
|
|
20972
|
+
name: "GPT-5.6-Sol-1M",
|
|
20973
|
+
capabilityClass: "flagship",
|
|
20974
|
+
providerModelId: "gpt-5.6-sol",
|
|
20975
|
+
contextWindow: 1e6,
|
|
20976
|
+
effort: {
|
|
20977
|
+
supported: true,
|
|
20978
|
+
levels: [
|
|
20979
|
+
"low",
|
|
20980
|
+
"medium",
|
|
20981
|
+
"high",
|
|
20982
|
+
"xhigh",
|
|
20983
|
+
"max"
|
|
20984
|
+
]
|
|
20985
|
+
},
|
|
20986
|
+
aliases: [
|
|
20987
|
+
"gpt-5.6-sol-1m"
|
|
20988
|
+
],
|
|
20989
|
+
benchmarkKey: "gpt-5.6-sol"
|
|
20990
|
+
},
|
|
20991
|
+
{
|
|
20992
|
+
modelId: "gpt-5.6-sol-1m-fast",
|
|
20993
|
+
name: "GPT-5.6-Sol-1M-Fast",
|
|
20994
|
+
capabilityClass: "flagship",
|
|
20995
|
+
providerModelId: "gpt-5.6-sol",
|
|
20996
|
+
serviceTier: "priority",
|
|
20997
|
+
contextWindow: 1e6,
|
|
20998
|
+
effort: {
|
|
20999
|
+
supported: true,
|
|
21000
|
+
levels: [
|
|
21001
|
+
"low",
|
|
21002
|
+
"medium",
|
|
21003
|
+
"high",
|
|
21004
|
+
"xhigh",
|
|
21005
|
+
"max"
|
|
21006
|
+
]
|
|
21007
|
+
},
|
|
21008
|
+
aliases: [
|
|
21009
|
+
"gpt-5.6-sol-1m-fast"
|
|
21010
|
+
],
|
|
21011
|
+
benchmarkKey: "gpt-5.6-sol"
|
|
21012
|
+
},
|
|
21013
|
+
{
|
|
21014
|
+
modelId: "gpt-5.6-luna-1m",
|
|
21015
|
+
name: "GPT-5.6-Luna-1M",
|
|
21016
|
+
capabilityClass: "light",
|
|
21017
|
+
providerModelId: "gpt-5.6-luna",
|
|
21018
|
+
contextWindow: 1e6,
|
|
21019
|
+
effort: {
|
|
21020
|
+
supported: true,
|
|
21021
|
+
levels: [
|
|
21022
|
+
"low",
|
|
21023
|
+
"medium",
|
|
21024
|
+
"high",
|
|
21025
|
+
"xhigh",
|
|
21026
|
+
"max"
|
|
21027
|
+
]
|
|
21028
|
+
},
|
|
21029
|
+
aliases: [
|
|
21030
|
+
"gpt-5.6-luna-1m"
|
|
21031
|
+
],
|
|
21032
|
+
benchmarkKey: "gpt-5.6-luna"
|
|
21033
|
+
},
|
|
21034
|
+
{
|
|
21035
|
+
modelId: "gpt-5.6-luna-1m-fast",
|
|
21036
|
+
name: "GPT-5.6-Luna-1M-Fast",
|
|
21037
|
+
capabilityClass: "light",
|
|
21038
|
+
providerModelId: "gpt-5.6-luna",
|
|
21039
|
+
serviceTier: "priority",
|
|
21040
|
+
contextWindow: 1e6,
|
|
21041
|
+
effort: {
|
|
21042
|
+
supported: true,
|
|
21043
|
+
levels: [
|
|
21044
|
+
"low",
|
|
21045
|
+
"medium",
|
|
21046
|
+
"high",
|
|
21047
|
+
"xhigh",
|
|
21048
|
+
"max"
|
|
21049
|
+
]
|
|
21050
|
+
},
|
|
21051
|
+
aliases: [
|
|
21052
|
+
"gpt-5.6-luna-1m-fast"
|
|
21053
|
+
],
|
|
21054
|
+
benchmarkKey: "gpt-5.6-luna"
|
|
21055
|
+
},
|
|
21056
|
+
{
|
|
21057
|
+
modelId: "gpt-5.6-terra-1m",
|
|
21058
|
+
name: "GPT-5.6-Terra-1M",
|
|
21059
|
+
capabilityClass: "standard",
|
|
21060
|
+
providerModelId: "gpt-5.6-terra",
|
|
21061
|
+
contextWindow: 1e6,
|
|
21062
|
+
effort: {
|
|
21063
|
+
supported: true,
|
|
21064
|
+
levels: [
|
|
21065
|
+
"low",
|
|
21066
|
+
"medium",
|
|
21067
|
+
"high",
|
|
21068
|
+
"xhigh",
|
|
21069
|
+
"max"
|
|
21070
|
+
]
|
|
21071
|
+
},
|
|
21072
|
+
aliases: [
|
|
21073
|
+
"gpt-5.6-terra-1m"
|
|
21074
|
+
],
|
|
21075
|
+
benchmarkKey: "gpt-5.6-terra"
|
|
21076
|
+
},
|
|
21077
|
+
{
|
|
21078
|
+
modelId: "gpt-5.6-terra-1m-fast",
|
|
21079
|
+
name: "GPT-5.6-Terra-1M-Fast",
|
|
21080
|
+
capabilityClass: "standard",
|
|
21081
|
+
providerModelId: "gpt-5.6-terra",
|
|
21082
|
+
serviceTier: "priority",
|
|
21083
|
+
contextWindow: 1e6,
|
|
21084
|
+
effort: {
|
|
21085
|
+
supported: true,
|
|
21086
|
+
levels: [
|
|
21087
|
+
"low",
|
|
21088
|
+
"medium",
|
|
21089
|
+
"high",
|
|
21090
|
+
"xhigh",
|
|
21091
|
+
"max"
|
|
21092
|
+
]
|
|
21093
|
+
},
|
|
21094
|
+
aliases: [
|
|
21095
|
+
"gpt-5.6-terra-1m-fast"
|
|
21096
|
+
],
|
|
21097
|
+
benchmarkKey: "gpt-5.6-terra"
|
|
20969
21098
|
}
|
|
20970
21099
|
]
|
|
20971
21100
|
},
|
|
@@ -45652,6 +45781,9 @@ var CLAUDE_GATEWAY_TURN_KEYS = Object.freeze([
|
|
|
45652
45781
|
"abortController",
|
|
45653
45782
|
"stderr"
|
|
45654
45783
|
]);
|
|
45784
|
+
var CLAUDE_GATEWAY_SESSION_KEYS = Object.freeze(
|
|
45785
|
+
CLAUDE_GATEWAY_TURN_KEYS.filter((key) => key !== "prompt")
|
|
45786
|
+
);
|
|
45655
45787
|
|
|
45656
45788
|
// ../../packages/core-agent/src/claude/launch-env.ts
|
|
45657
45789
|
var CLAUDE_GATEWAY_MODEL_CACHE_RELPATH = "cache/gateway-models.json";
|
|
@@ -45773,6 +45905,111 @@ function runVendorQuery(input) {
|
|
|
45773
45905
|
}
|
|
45774
45906
|
};
|
|
45775
45907
|
}
|
|
45908
|
+
var VendorInputQueue = class {
|
|
45909
|
+
pending = [];
|
|
45910
|
+
waiting = null;
|
|
45911
|
+
closed = false;
|
|
45912
|
+
push(message) {
|
|
45913
|
+
if (this.closed) return;
|
|
45914
|
+
const waiting = this.waiting;
|
|
45915
|
+
if (waiting) {
|
|
45916
|
+
this.waiting = null;
|
|
45917
|
+
waiting({ done: false, value: message });
|
|
45918
|
+
return;
|
|
45919
|
+
}
|
|
45920
|
+
this.pending.push(message);
|
|
45921
|
+
}
|
|
45922
|
+
close() {
|
|
45923
|
+
if (this.closed) return;
|
|
45924
|
+
this.closed = true;
|
|
45925
|
+
const waiting = this.waiting;
|
|
45926
|
+
if (waiting) {
|
|
45927
|
+
this.waiting = null;
|
|
45928
|
+
waiting({ done: true, value: void 0 });
|
|
45929
|
+
}
|
|
45930
|
+
}
|
|
45931
|
+
[Symbol.asyncIterator]() {
|
|
45932
|
+
return {
|
|
45933
|
+
next: async () => {
|
|
45934
|
+
if (this.pending.length > 0) return { done: false, value: this.pending.shift() };
|
|
45935
|
+
if (this.closed) return { done: true, value: void 0 };
|
|
45936
|
+
return await new Promise((resolve3) => {
|
|
45937
|
+
this.waiting = resolve3;
|
|
45938
|
+
});
|
|
45939
|
+
}
|
|
45940
|
+
};
|
|
45941
|
+
}
|
|
45942
|
+
};
|
|
45943
|
+
function vendorUserMessage(text2) {
|
|
45944
|
+
return {
|
|
45945
|
+
type: "user",
|
|
45946
|
+
session_id: "",
|
|
45947
|
+
message: { role: "user", content: [{ type: "text", text: text2 }] },
|
|
45948
|
+
parent_tool_use_id: null
|
|
45949
|
+
};
|
|
45950
|
+
}
|
|
45951
|
+
function runVendorSession(input) {
|
|
45952
|
+
const queue = new VendorInputQueue();
|
|
45953
|
+
const run = query({
|
|
45954
|
+
prompt: queue,
|
|
45955
|
+
options: input.options
|
|
45956
|
+
});
|
|
45957
|
+
let closed = false;
|
|
45958
|
+
return {
|
|
45959
|
+
send(text2) {
|
|
45960
|
+
if (closed) return;
|
|
45961
|
+
queue.push(vendorUserMessage(text2));
|
|
45962
|
+
},
|
|
45963
|
+
async interrupt() {
|
|
45964
|
+
if (closed || typeof run.interrupt !== "function") return;
|
|
45965
|
+
await run.interrupt();
|
|
45966
|
+
},
|
|
45967
|
+
async stopTask(taskId) {
|
|
45968
|
+
if (closed) return;
|
|
45969
|
+
if (typeof run.stopTask !== "function") {
|
|
45970
|
+
throw new TypeError("This Claude Agent SDK build has no stopTask control request.");
|
|
45971
|
+
}
|
|
45972
|
+
await run.stopTask(taskId);
|
|
45973
|
+
},
|
|
45974
|
+
async backgroundTasks(toolUseId) {
|
|
45975
|
+
if (closed) return false;
|
|
45976
|
+
if (typeof run.backgroundTasks !== "function") {
|
|
45977
|
+
throw new TypeError("This Claude Agent SDK build has no background_tasks control request.");
|
|
45978
|
+
}
|
|
45979
|
+
return await run.backgroundTasks(toolUseId);
|
|
45980
|
+
},
|
|
45981
|
+
async getContextUsage() {
|
|
45982
|
+
if (closed || typeof run.getContextUsage !== "function") return null;
|
|
45983
|
+
try {
|
|
45984
|
+
return readVendorContextUsage(await run.getContextUsage());
|
|
45985
|
+
} catch {
|
|
45986
|
+
return null;
|
|
45987
|
+
}
|
|
45988
|
+
},
|
|
45989
|
+
[Symbol.asyncIterator]() {
|
|
45990
|
+
const iterator = run[Symbol.asyncIterator]();
|
|
45991
|
+
return {
|
|
45992
|
+
async next() {
|
|
45993
|
+
const result = await iterator.next();
|
|
45994
|
+
return result.done === true ? { done: true, value: void 0 } : { done: false, value: result.value };
|
|
45995
|
+
}
|
|
45996
|
+
};
|
|
45997
|
+
},
|
|
45998
|
+
close() {
|
|
45999
|
+
if (closed) return;
|
|
46000
|
+
closed = true;
|
|
46001
|
+
queue.close();
|
|
46002
|
+
try {
|
|
46003
|
+
if (typeof run.close === "function") run.close();
|
|
46004
|
+
else {
|
|
46005
|
+
const closing = run.return?.(void 0);
|
|
46006
|
+
if (closing !== void 0) void closing.catch(() => void 0);
|
|
46007
|
+
}
|
|
46008
|
+
} catch {
|
|
46009
|
+
}
|
|
46010
|
+
}
|
|
46011
|
+
};
|
|
46012
|
+
}
|
|
45776
46013
|
function defineVendorTool(name, description, inputSchema, handler, extras) {
|
|
45777
46014
|
const definition = tool(
|
|
45778
46015
|
name,
|
|
@@ -45807,80 +46044,135 @@ async function createClaudeGatewaySdk(options) {
|
|
|
45807
46044
|
const configDir = options.home?.kind === "shared" ? createSharedClaudeConfigHome(options.home.configDir) : await createIsolatedClaudeConfigDir(options.tempRoot);
|
|
45808
46045
|
let disposed = false;
|
|
45809
46046
|
let active = null;
|
|
46047
|
+
const reserveSlot = (kind) => {
|
|
46048
|
+
if (disposed) throw new Error("This Claude gateway SDK instance has been disposed.");
|
|
46049
|
+
if (active) {
|
|
46050
|
+
throw new Error(kind === "turn" ? "A turn is already running on this instance. Await it, or create another instance." : "A turn or session is already running on this instance. Close it, or create another instance.");
|
|
46051
|
+
}
|
|
46052
|
+
const reservation = { close: () => void 0 };
|
|
46053
|
+
active = reservation;
|
|
46054
|
+
return reservation;
|
|
46055
|
+
};
|
|
46056
|
+
const prepareLaunch = async () => {
|
|
46057
|
+
await configDir.writeModelCache({ baseUrl, models: catalogModels, fetchedAt: Date.now() });
|
|
46058
|
+
return claudeGatewayLaunchEnv(inherited, {
|
|
46059
|
+
baseUrl,
|
|
46060
|
+
configDir: configDir.path,
|
|
46061
|
+
homeKind: options.home?.kind === "shared" ? "shared" : "isolated"
|
|
46062
|
+
});
|
|
46063
|
+
};
|
|
46064
|
+
const vendorRunOptions = (request, model, env) => ({
|
|
46065
|
+
env,
|
|
46066
|
+
model,
|
|
46067
|
+
...request.systemPrompt === void 0 ? {} : { systemPrompt: vendorSystemPrompt(request.systemPrompt) },
|
|
46068
|
+
// 패키지가 스스로 지어내는 지시는 없다 — 여기 실리는 것은 전부 호출자가 고른 것이고,
|
|
46069
|
+
// 고르지 않으면 아무것도 붙지 않는다. 두 기본값이 그 규율을 구조로 만든다:
|
|
46070
|
+
// `settingSources: []`가 사용자·프로젝트 설정과 CLAUDE.md를 끄고, `strictMcpConfig`가
|
|
46071
|
+
// 그와 별개인 ambient .mcp.json·플러그인 MCP를 막는다.
|
|
46072
|
+
settingSources: options.settingSources ? [...options.settingSources] : [],
|
|
46073
|
+
strictMcpConfig: options.allowAmbientMcpServers !== true,
|
|
46074
|
+
// 플러그인의 MCP 선언은 읽지 않는다 — 좌표는 호출자가 이미 소유한다.
|
|
46075
|
+
...options.plugins && options.plugins.length > 0 ? { plugins: options.plugins.map((plugin) => ({ type: "local", path: plugin.path, skipMcpDiscovery: true })) } : {},
|
|
46076
|
+
// `--settings`와 같은 자리다. flag 소스로 병합되므로 사용자·프로젝트 설정을 대체하지 않는다.
|
|
46077
|
+
// skillOverrides와 ultracode만 연다 — settings 전체를 열면 호출자가 쓰지 않은 지시가 들어온다.
|
|
46078
|
+
...vendorFlagSettings(options),
|
|
46079
|
+
...request.effort === void 0 ? {} : { effort: request.effort },
|
|
46080
|
+
...request.cwd === void 0 ? {} : { cwd: request.cwd },
|
|
46081
|
+
...request.resume === void 0 ? {} : { resume: request.resume },
|
|
46082
|
+
...request.maxTurns === void 0 ? {} : { maxTurns: request.maxTurns },
|
|
46083
|
+
...request.maxBudgetUsd === void 0 ? {} : { maxBudgetUsd: request.maxBudgetUsd },
|
|
46084
|
+
...request.tools === void 0 ? {} : { tools: [...request.tools] },
|
|
46085
|
+
...request.allowedTools === void 0 ? {} : { allowedTools: [...request.allowedTools] },
|
|
46086
|
+
...request.disallowedTools === void 0 ? {} : { disallowedTools: [...request.disallowedTools] },
|
|
46087
|
+
...request.permissionMode === void 0 ? {} : { permissionMode: request.permissionMode },
|
|
46088
|
+
...request.canUseTool === void 0 ? {} : { canUseTool: vendorCanUseTool(request.canUseTool) },
|
|
46089
|
+
...request.mcpServers === void 0 && request.servedMcpServers === void 0 ? {} : { mcpServers: { ...request.mcpServers, ...vendorServedMcpServers(request.servedMcpServers) } },
|
|
46090
|
+
...request.includePartialMessages === void 0 ? {} : { includePartialMessages: request.includePartialMessages },
|
|
46091
|
+
...request.abortController === void 0 ? {} : { abortController: request.abortController },
|
|
46092
|
+
...request.stderr === void 0 ? {} : { stderr: request.stderr }
|
|
46093
|
+
});
|
|
45810
46094
|
const sdk = {
|
|
45811
46095
|
configDir: configDir.path,
|
|
45812
46096
|
models: Object.freeze(accepted.map((entry) => entry.id)),
|
|
45813
46097
|
async startTurn(turn) {
|
|
45814
|
-
|
|
45815
|
-
|
|
45816
|
-
|
|
45817
|
-
|
|
45818
|
-
|
|
45819
|
-
|
|
45820
|
-
|
|
45821
|
-
|
|
45822
|
-
|
|
45823
|
-
|
|
45824
|
-
|
|
45825
|
-
|
|
45826
|
-
|
|
45827
|
-
|
|
45828
|
-
|
|
45829
|
-
|
|
45830
|
-
|
|
45831
|
-
|
|
45832
|
-
|
|
45833
|
-
|
|
45834
|
-
|
|
45835
|
-
|
|
45836
|
-
|
|
45837
|
-
|
|
45838
|
-
|
|
45839
|
-
|
|
45840
|
-
|
|
45841
|
-
|
|
45842
|
-
|
|
45843
|
-
|
|
45844
|
-
|
|
45845
|
-
|
|
45846
|
-
|
|
45847
|
-
|
|
45848
|
-
|
|
45849
|
-
|
|
45850
|
-
|
|
45851
|
-
|
|
45852
|
-
...turn.canUseTool === void 0 ? {} : { canUseTool: vendorCanUseTool(turn.canUseTool) },
|
|
45853
|
-
...turn.mcpServers === void 0 && turn.servedMcpServers === void 0 ? {} : { mcpServers: { ...turn.mcpServers, ...vendorServedMcpServers(turn.servedMcpServers) } },
|
|
45854
|
-
...turn.includePartialMessages === void 0 ? {} : { includePartialMessages: turn.includePartialMessages },
|
|
45855
|
-
...turn.abortController === void 0 ? {} : { abortController: turn.abortController },
|
|
45856
|
-
...turn.stderr === void 0 ? {} : { stderr: turn.stderr }
|
|
46098
|
+
const reservation = reserveSlot("turn");
|
|
46099
|
+
try {
|
|
46100
|
+
assertKnownTurnKeys(turn);
|
|
46101
|
+
if (typeof turn.prompt !== "string" || turn.prompt.length === 0) {
|
|
46102
|
+
throw new TypeError("turn.prompt must be a non-empty string.");
|
|
46103
|
+
}
|
|
46104
|
+
const model = resolveTurnModel(turn.model, accepted);
|
|
46105
|
+
const env = await prepareLaunch();
|
|
46106
|
+
const run = runVendorQuery({
|
|
46107
|
+
prompt: turn.prompt,
|
|
46108
|
+
options: vendorRunOptions(turn, model, env)
|
|
46109
|
+
});
|
|
46110
|
+
const release = () => {
|
|
46111
|
+
if (active === tracked) active = null;
|
|
46112
|
+
};
|
|
46113
|
+
const tracked = {
|
|
46114
|
+
[Symbol.asyncIterator]() {
|
|
46115
|
+
const iterator = run[Symbol.asyncIterator]();
|
|
46116
|
+
return {
|
|
46117
|
+
async next() {
|
|
46118
|
+
const result = await iterator.next();
|
|
46119
|
+
if (result.done === true) release();
|
|
46120
|
+
return result;
|
|
46121
|
+
}
|
|
46122
|
+
};
|
|
46123
|
+
},
|
|
46124
|
+
close() {
|
|
46125
|
+
try {
|
|
46126
|
+
run.close();
|
|
46127
|
+
} finally {
|
|
46128
|
+
release();
|
|
46129
|
+
}
|
|
46130
|
+
},
|
|
46131
|
+
getContextUsage: () => run.getContextUsage()
|
|
46132
|
+
};
|
|
46133
|
+
if (active !== reservation) {
|
|
46134
|
+
run.close();
|
|
46135
|
+
throw new Error("This Claude gateway SDK instance has been disposed.");
|
|
45857
46136
|
}
|
|
45858
|
-
|
|
45859
|
-
|
|
45860
|
-
|
|
45861
|
-
|
|
45862
|
-
|
|
45863
|
-
|
|
45864
|
-
|
|
45865
|
-
|
|
45866
|
-
|
|
45867
|
-
|
|
45868
|
-
|
|
45869
|
-
|
|
46137
|
+
active = tracked;
|
|
46138
|
+
return tracked;
|
|
46139
|
+
} catch (error51) {
|
|
46140
|
+
if (active === reservation) active = null;
|
|
46141
|
+
throw error51;
|
|
46142
|
+
}
|
|
46143
|
+
},
|
|
46144
|
+
async openSession(request) {
|
|
46145
|
+
const reservation = reserveSlot("session");
|
|
46146
|
+
try {
|
|
46147
|
+
assertKnownSessionKeys(request);
|
|
46148
|
+
const model = resolveTurnModel(request.model, accepted);
|
|
46149
|
+
const env = await prepareLaunch();
|
|
46150
|
+
const session = runVendorSession({ options: vendorRunOptions(request, model, env) });
|
|
46151
|
+
const tracked = {
|
|
46152
|
+
send: (text2) => session.send(text2),
|
|
46153
|
+
interrupt: () => session.interrupt(),
|
|
46154
|
+
stopTask: (taskId) => session.stopTask(taskId),
|
|
46155
|
+
backgroundTasks: (toolUseId) => session.backgroundTasks(toolUseId),
|
|
46156
|
+
getContextUsage: () => session.getContextUsage(),
|
|
46157
|
+
[Symbol.asyncIterator]: () => session[Symbol.asyncIterator](),
|
|
46158
|
+
close() {
|
|
46159
|
+
try {
|
|
46160
|
+
session.close();
|
|
46161
|
+
} finally {
|
|
46162
|
+
if (active === tracked) active = null;
|
|
45870
46163
|
}
|
|
45871
|
-
};
|
|
45872
|
-
},
|
|
45873
|
-
close() {
|
|
45874
|
-
try {
|
|
45875
|
-
run.close();
|
|
45876
|
-
} finally {
|
|
45877
|
-
release();
|
|
45878
46164
|
}
|
|
45879
|
-
}
|
|
45880
|
-
|
|
45881
|
-
|
|
45882
|
-
|
|
45883
|
-
|
|
46165
|
+
};
|
|
46166
|
+
if (active !== reservation) {
|
|
46167
|
+
session.close();
|
|
46168
|
+
throw new Error("This Claude gateway SDK instance has been disposed.");
|
|
46169
|
+
}
|
|
46170
|
+
active = tracked;
|
|
46171
|
+
return tracked;
|
|
46172
|
+
} catch (error51) {
|
|
46173
|
+
if (active === reservation) active = null;
|
|
46174
|
+
throw error51;
|
|
46175
|
+
}
|
|
45884
46176
|
},
|
|
45885
46177
|
async dispose() {
|
|
45886
46178
|
if (disposed) return;
|
|
@@ -45962,6 +46254,14 @@ function vendorCanUseTool(canUseTool) {
|
|
|
45962
46254
|
}
|
|
45963
46255
|
};
|
|
45964
46256
|
}
|
|
46257
|
+
function vendorFlagSettings(options) {
|
|
46258
|
+
const settings2 = {};
|
|
46259
|
+
if (options.skillOverrides && Object.keys(options.skillOverrides).length > 0) {
|
|
46260
|
+
settings2.skillOverrides = { ...options.skillOverrides };
|
|
46261
|
+
}
|
|
46262
|
+
if (options.ultracode === true) settings2.ultracode = true;
|
|
46263
|
+
return Object.keys(settings2).length > 0 ? { settings: settings2 } : {};
|
|
46264
|
+
}
|
|
45965
46265
|
function vendorSystemPrompt(systemPrompt) {
|
|
45966
46266
|
const text2 = systemPrompt?.text;
|
|
45967
46267
|
if (typeof text2 !== "string" || text2.length === 0) {
|
|
@@ -45979,6 +46279,14 @@ function assertKnownTurnKeys(turn) {
|
|
|
45979
46279
|
);
|
|
45980
46280
|
}
|
|
45981
46281
|
}
|
|
46282
|
+
function assertKnownSessionKeys(request) {
|
|
46283
|
+
const unknown2 = Object.keys(request).filter((key) => !CLAUDE_GATEWAY_SESSION_KEYS.includes(key));
|
|
46284
|
+
if (unknown2.length > 0) {
|
|
46285
|
+
throw new TypeError(
|
|
46286
|
+
`Unsupported session option(s): ${unknown2.join(", ")}. Only an instruction the caller authored may reach the child, through systemPrompt; every other instruction channel is closed, so those options do not exist. A session receives its prompts through send(), never as an option.`
|
|
46287
|
+
);
|
|
46288
|
+
}
|
|
46289
|
+
}
|
|
45982
46290
|
function vendorServedMcpServers(servers) {
|
|
45983
46291
|
if (!servers?.length) return {};
|
|
45984
46292
|
return Object.fromEntries(servers.map((server) => [server.name, {
|
|
@@ -47469,6 +47777,14 @@ function readAnalysisProviderSession(value) {
|
|
|
47469
47777
|
...typeof candidate.source === "string" ? { source: candidate.source } : {}
|
|
47470
47778
|
};
|
|
47471
47779
|
}
|
|
47780
|
+
|
|
47781
|
+
// ../fleet-plugins/terminal/server/agent-api/chat-launch-effort.ts
|
|
47782
|
+
var WIRE_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
47783
|
+
function resolveChatLaunchEffort(value) {
|
|
47784
|
+
if (value.length === 0) return void 0;
|
|
47785
|
+
if (value === "ultra") return { effort: "xhigh", ultracode: true };
|
|
47786
|
+
return WIRE_EFFORTS.includes(value) ? { effort: value } : void 0;
|
|
47787
|
+
}
|
|
47472
47788
|
var MAX_TOOL_DETAIL_CHARS = 160;
|
|
47473
47789
|
var MAX_TOOL_RESULT_CHARS = 120;
|
|
47474
47790
|
var MAX_TEXT_CHARS = 6e4;
|
|
@@ -47518,6 +47834,9 @@ function eventsFromTranscriptLine(line, options) {
|
|
|
47518
47834
|
return [];
|
|
47519
47835
|
}
|
|
47520
47836
|
function chatEventsFromSdkMessage(message, options = {}) {
|
|
47837
|
+
if (typeof message.parent_tool_use_id === "string" && message.parent_tool_use_id.length > 0) {
|
|
47838
|
+
return [];
|
|
47839
|
+
}
|
|
47521
47840
|
if (message.type === "stream_event") {
|
|
47522
47841
|
const inner = message.event;
|
|
47523
47842
|
if (!inner || typeof inner !== "object") return [];
|
|
@@ -48067,6 +48386,10 @@ var AgentChatSession = class {
|
|
|
48067
48386
|
latestSessionId;
|
|
48068
48387
|
/** 이미 Operation에 심은 세션 id. 같은 좌표를 매 턴 다시 심지 않기 위한 축이다. */
|
|
48069
48388
|
reportedSessionId = null;
|
|
48389
|
+
/** 날고 있는 좌표 심기. 리더가 메시지마다 이 자리를 지나므로 겹치지 않게 붙든다. */
|
|
48390
|
+
syncFlight = null;
|
|
48391
|
+
/** 그 비행 중에 들어온 요청이 있었다. 착지 후 좌표가 아직 남아 있으면 한 번 더 간다. */
|
|
48392
|
+
syncDirty = false;
|
|
48070
48393
|
journal = [];
|
|
48071
48394
|
seq = 0;
|
|
48072
48395
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -48074,11 +48397,52 @@ var AgentChatSession = class {
|
|
|
48074
48397
|
pendingTurns = 0;
|
|
48075
48398
|
disposed = false;
|
|
48076
48399
|
/**
|
|
48077
|
-
*
|
|
48078
|
-
*
|
|
48079
|
-
*
|
|
48400
|
+
* 이 세션이 붙들고 있는 자식. 턴마다 세우고 접는 것이 아니라 **Operation이 열려 있는 동안**
|
|
48401
|
+
* 살아 있으며, 그 수명이 곧 백그라운드 작업의 수명이다 — 턴 단위 실행은 vendor가 single-turn으로
|
|
48402
|
+
* 보고 자식의 입력을 닫아, Claude Code의 wind-down이 백그라운드 셸을 유예 뒤 kill한다.
|
|
48403
|
+
*/
|
|
48404
|
+
session = null;
|
|
48405
|
+
sessionFlight = null;
|
|
48406
|
+
/** 세션 스트림을 소진하는 리더. dispose가 착지를 기다리는 자리다. */
|
|
48407
|
+
readerDone = null;
|
|
48408
|
+
/**
|
|
48409
|
+
* 지금 화면에 열려 있는 턴이 있는가.
|
|
48410
|
+
*
|
|
48411
|
+
* 스트림이 턴마다 끝나지 않으므로 이 축이 필요하다. 여는 자리는 둘 — 사용자가 보낸 디스패치와,
|
|
48412
|
+
* 백그라운드 작업이 끝나 자식이 모델을 다시 깨운 뒤 흐르기 시작한 내용이다. 닫는 자리는 `result`
|
|
48413
|
+
* 하나이고, 중지도 여기를 닫는다.
|
|
48080
48414
|
*/
|
|
48081
|
-
|
|
48415
|
+
turnOpen = false;
|
|
48416
|
+
/** 열린 턴의 완주를 기다리는 디스패치. 턴이 닫히면 풀린다. */
|
|
48417
|
+
awaitingTurn = null;
|
|
48418
|
+
/**
|
|
48419
|
+
* 열린 턴이 닫히기를 기다리는 디스패치들.
|
|
48420
|
+
*
|
|
48421
|
+
* 자식이 백그라운드 완료로 스스로 깨어나 연 턴은 아무도 기다리지 않는다. 그 창에 사용자
|
|
48422
|
+
* 메시지가 들어오면 자기 턴을 세우지 못한 채 남의 결말에 실려 나가므로, 여기서 줄을 세운다.
|
|
48423
|
+
*/
|
|
48424
|
+
turnCloseWaiters = /* @__PURE__ */ new Set();
|
|
48425
|
+
/**
|
|
48426
|
+
* 중지한 턴이 아직 자기 `result`를 내지 않았다.
|
|
48427
|
+
*
|
|
48428
|
+
* 자식은 중단을 받아도 그 턴의 결말을 **반드시** 낸다(실측: `interrupt()` 뒤 2ms에
|
|
48429
|
+
* `error_during_execution`). 그것은 이미 닫은 턴의 것이므로 새 턴의 결말로 읽으면 안 되고,
|
|
48430
|
+
* 그 사이에 들어온 디스패치는 그 한 건이 지나갈 때까지 기다린다.
|
|
48431
|
+
*/
|
|
48432
|
+
settlingStoppedTurn = false;
|
|
48433
|
+
/**
|
|
48434
|
+
* 지금 열린 턴의 프롬프트가 자식에 실제로 닿았는가.
|
|
48435
|
+
*
|
|
48436
|
+
* 닿지 않은 턴에는 자식이 낼 결말도 없다 — 세션을 여는 동안(자식 spawn·플러그인·MCP 발급은
|
|
48437
|
+
* 몇 초가 걸린다) 사용자가 중지하면 그 턴은 자식이 존재조차 모른 채 닫힌다. 그때 결말을
|
|
48438
|
+
* 기다리기 시작하면 오지 않을 것을 기다리며 세션이 영구히 막힌다.
|
|
48439
|
+
*/
|
|
48440
|
+
turnReachedChild = false;
|
|
48441
|
+
/**
|
|
48442
|
+
* 지금 살아 있다고 알려진 잡. 세션이 끊기면 이 잡들은 자식과 함께 사라지므로, 원장에 "도는 중"
|
|
48443
|
+
* 으로 남겨 두지 않고 거둬진 것으로 닫는다 — 화면이 없는 작업을 기다리게 두지 않기 위해서다.
|
|
48444
|
+
*/
|
|
48445
|
+
liveJobs = /* @__PURE__ */ new Set();
|
|
48082
48446
|
/**
|
|
48083
48447
|
* 중지 세대. 중지는 도는 턴 하나가 아니라 **그 시점의 큐 전체**를 끊어야 한다 — 큐에 밀려
|
|
48084
48448
|
* 있던 턴이 중지 직후 태연히 시작하면, 사용자가 멈춘 것은 화면에서 멈추지 않는다. 각 턴은
|
|
@@ -48180,31 +48544,49 @@ var AgentChatSession = class {
|
|
|
48180
48544
|
if (this.disposed) return;
|
|
48181
48545
|
const epoch = this.stopEpoch;
|
|
48182
48546
|
this.pendingTurns += 1;
|
|
48183
|
-
this.turnFlight = this.turnFlight.then(() => epoch === this.stopEpoch ? this.
|
|
48547
|
+
this.turnFlight = this.turnFlight.then(() => epoch === this.stopEpoch ? this.dispatch(text2) : void 0).catch(() => void 0).finally(() => {
|
|
48184
48548
|
this.pendingTurns -= 1;
|
|
48185
48549
|
});
|
|
48186
48550
|
}
|
|
48187
48551
|
/**
|
|
48188
48552
|
* 도는 턴을 사용자가 끊는다.
|
|
48189
48553
|
*
|
|
48190
|
-
* 이 자리가 여는 문은 **턴 하나**다.
|
|
48191
|
-
*
|
|
48192
|
-
* 멈추는 척하지 않는다 — 턴을 끊어도 이미 태어난 백그라운드 작업은 계속 살고, 원장의 잡
|
|
48193
|
-
* 표면이 그것을 그대로 말한다.
|
|
48554
|
+
* 이 자리가 여는 문은 **턴 하나**다. 자식은 죽지 않으며, 이미 태어난 백그라운드 작업도 계속
|
|
48555
|
+
* 산다 — 그것을 멈추는 문은 `stopJob`이 따로 연다. 턴만 끊는 것이 CLI의 Esc와 같은 자리다.
|
|
48194
48556
|
*
|
|
48195
48557
|
* 돌려주는 값은 "끊을 것이 있었는가"다. 없는데 true를 돌려주면 화면이 멈춤을 그리고 아무 일도
|
|
48196
48558
|
* 일어나지 않는다.
|
|
48197
48559
|
*/
|
|
48198
48560
|
stopTurn() {
|
|
48199
48561
|
if (this.disposed) return false;
|
|
48200
|
-
if (this.pendingTurns === 0) return false;
|
|
48562
|
+
if (this.pendingTurns === 0 && !this.turnOpen) return false;
|
|
48201
48563
|
this.stopEpoch += 1;
|
|
48202
|
-
const run = this.activeRun;
|
|
48203
|
-
this.activeRun = null;
|
|
48204
48564
|
this.abandonAsks("The turn was stopped before the question was answered.");
|
|
48205
|
-
|
|
48565
|
+
void this.session?.interrupt().catch(() => void 0);
|
|
48566
|
+
if (this.turnOpen && this.turnReachedChild) this.settlingStoppedTurn = true;
|
|
48567
|
+
this.closeTurn({ stopped: true });
|
|
48206
48568
|
return true;
|
|
48207
48569
|
}
|
|
48570
|
+
/**
|
|
48571
|
+
* 백그라운드 작업 하나를 사용자가 멈춘다.
|
|
48572
|
+
*
|
|
48573
|
+
* 좌표는 SDK가 발급한 `task_id`이며, 우리가 그 잡을 실제로 본 적이 있어야 한다(`jobKinds`가
|
|
48574
|
+
* 그 문이다) — 브라우저가 지어낸 id는 자식에 닿지 않는다. 결말은 자식이 내는 `stopped` 알림이
|
|
48575
|
+
* 말하므로, 여기서 원장을 미리 고쳐 쓰지 않는다.
|
|
48576
|
+
*/
|
|
48577
|
+
async stopJob(jobId) {
|
|
48578
|
+
if (this.disposed) return false;
|
|
48579
|
+
if (!/^[A-Za-z0-9_-]{1,128}$/.test(jobId)) return false;
|
|
48580
|
+
if (!this.jobKinds.has(jobId)) return false;
|
|
48581
|
+
const session = this.session;
|
|
48582
|
+
if (!session) return false;
|
|
48583
|
+
try {
|
|
48584
|
+
await session.stopTask(jobId);
|
|
48585
|
+
return true;
|
|
48586
|
+
} catch {
|
|
48587
|
+
return false;
|
|
48588
|
+
}
|
|
48589
|
+
}
|
|
48208
48590
|
/** 지금 답을 기다리는 도구 호출이 있는가. 라우트가 대기 유무를 묻는 자리. */
|
|
48209
48591
|
get awaiting() {
|
|
48210
48592
|
return this.pendingAsks.size > 0;
|
|
@@ -48283,10 +48665,16 @@ var AgentChatSession = class {
|
|
|
48283
48665
|
if (this.disposed) return;
|
|
48284
48666
|
this.disposed = true;
|
|
48285
48667
|
this.abandonAsks("The chat session closed before the question was answered.");
|
|
48668
|
+
const session = this.session;
|
|
48669
|
+
this.session = null;
|
|
48670
|
+
session?.close();
|
|
48286
48671
|
const sdk = this.sdk;
|
|
48287
48672
|
this.sdk = null;
|
|
48288
48673
|
if (sdk) await sdk.dispose().catch(() => void 0);
|
|
48674
|
+
if (this.readerDone) await this.readerDone.catch(() => void 0);
|
|
48675
|
+
this.releaseTurnCloseWaiters();
|
|
48289
48676
|
await this.turnFlight.catch(() => void 0);
|
|
48677
|
+
if (this.syncFlight) await this.syncFlight.catch(() => void 0);
|
|
48290
48678
|
if (this.fleetMcpFlight) await this.fleetMcpFlight.catch(() => void 0);
|
|
48291
48679
|
this.seed.releaseFleetMcpServers?.();
|
|
48292
48680
|
this.listeners.clear();
|
|
@@ -48436,10 +48824,10 @@ var AgentChatSession = class {
|
|
|
48436
48824
|
* 응답을 기다리지 않는 이유는 스트림 때문이다: 여기서 await하면 첫 메시지 소비가 그만큼 늦다.
|
|
48437
48825
|
* 늦게 도착한 답도 같은 턴의 시작 시점 값이므로, 그때 실어도 뜻이 달라지지 않는다.
|
|
48438
48826
|
*/
|
|
48439
|
-
snapshotContextAtTurnStart(
|
|
48827
|
+
snapshotContextAtTurnStart(session) {
|
|
48440
48828
|
const generation = ++this.contextGeneration;
|
|
48441
48829
|
try {
|
|
48442
|
-
void
|
|
48830
|
+
void session.getContextUsage().then((usage4) => {
|
|
48443
48831
|
if (usage4 && generation === this.contextGeneration) this.pushContext(usage4);
|
|
48444
48832
|
}, () => void 0);
|
|
48445
48833
|
} catch {
|
|
@@ -48512,6 +48900,7 @@ var AgentChatSession = class {
|
|
|
48512
48900
|
settingSources: ["user", "project", "local"],
|
|
48513
48901
|
allowAmbientMcpServers: true,
|
|
48514
48902
|
...this.seed.skillOverrides ? { skillOverrides: this.seed.skillOverrides } : {},
|
|
48903
|
+
...this.seed.ultracode ? { ultracode: true } : {},
|
|
48515
48904
|
// 플러그인이 실은 훅은 세션 식별자로 자기 축을 찾는다. 이 자식에게는 그 식별자가
|
|
48516
48905
|
// 없어야 한다 — 상속된 값이 남으면 남의 세션 축에 보고한다.
|
|
48517
48906
|
env: chatChildEnv(process.env),
|
|
@@ -48548,88 +48937,229 @@ var AgentChatSession = class {
|
|
|
48548
48937
|
}
|
|
48549
48938
|
return this.fleetMcpFlight;
|
|
48550
48939
|
}
|
|
48551
|
-
|
|
48940
|
+
/**
|
|
48941
|
+
* 자식 하나를 열고, 그 스트림을 끝까지 소진하는 리더를 세운다. 세션당 한 번이다.
|
|
48942
|
+
*
|
|
48943
|
+
* 턴이 아니라 세션이 실행 정책을 소유한다 — 모델·강도·doctrine·도구 좌표·cwd는 자식이 사는
|
|
48944
|
+
* 동안 바뀌지 않고, 바뀌어야 한다면 그것은 이 세션을 접고 새로 여는 사건이다.
|
|
48945
|
+
*/
|
|
48946
|
+
async ensureSession() {
|
|
48947
|
+
if (this.session) return this.session;
|
|
48948
|
+
if (!this.sessionFlight) {
|
|
48949
|
+
this.sessionFlight = (async () => {
|
|
48950
|
+
const sdk = await this.ensureSdk();
|
|
48951
|
+
const fleetMcpServers = await this.ensureFleetMcpServers().catch(() => {
|
|
48952
|
+
this.push({ kind: "error", code: "chat_fleet_tools_unavailable" });
|
|
48953
|
+
return [];
|
|
48954
|
+
});
|
|
48955
|
+
const session = await sdk.openSession({
|
|
48956
|
+
model: this.seed.model,
|
|
48957
|
+
...this.seed.effort ? { effort: this.seed.effort } : {},
|
|
48958
|
+
...this.seed.systemPrompt ? { systemPrompt: this.seed.systemPrompt } : {},
|
|
48959
|
+
...fleetMcpServers.length > 0 ? { servedMcpServers: fleetMcpServers } : {},
|
|
48960
|
+
cwd: this.seed.cwd,
|
|
48961
|
+
// 이어붙일 좌표는 세션을 열 때 한 번 선다. 채팅으로 태어난 세션에는 그것이 없고,
|
|
48962
|
+
// SDK가 돌려주는 session_id가 그 자리를 채운다 — 자식이 사는 동안은 그 세션이 계속
|
|
48963
|
+
// 자라므로 매 턴 다시 이어붙일 일이 없다.
|
|
48964
|
+
...this.latestSessionId ? { resume: this.latestSessionId } : {},
|
|
48965
|
+
permissionMode: "bypassPermissions",
|
|
48966
|
+
// 이 콜백은 권한 게이트가 아니다. 모드는 그대로 bypass이고 평범한 도구는 여기서 그냥
|
|
48967
|
+
// 통과한다 — 콜백을 주는 이유는 그래야 자식이 대화형 도구를 갖기 때문이다(실측: 29→32).
|
|
48968
|
+
canUseTool: (name, input, context) => this.askUser(name, input, context),
|
|
48969
|
+
// 스트리밍 감각의 근거 — 글자 단위 text_delta를 받으려면 부분 메시지가 필요하다.
|
|
48970
|
+
includePartialMessages: true
|
|
48971
|
+
});
|
|
48972
|
+
if (this.disposed) {
|
|
48973
|
+
session.close();
|
|
48974
|
+
throw new Error("chat session disposed");
|
|
48975
|
+
}
|
|
48976
|
+
this.session = session;
|
|
48977
|
+
this.readerDone = this.readSession(session);
|
|
48978
|
+
return session;
|
|
48979
|
+
})().finally(() => {
|
|
48980
|
+
this.sessionFlight = null;
|
|
48981
|
+
});
|
|
48982
|
+
}
|
|
48983
|
+
return this.sessionFlight;
|
|
48984
|
+
}
|
|
48985
|
+
/**
|
|
48986
|
+
* 세션 스트림을 끝까지 읽는다. 이 루프가 사는 동안 자식은 "사용자가 아직 있다"고 보므로,
|
|
48987
|
+
* 백그라운드 작업이 턴을 넘어 살고 그 결말 알림도 받을 자리가 있다.
|
|
48988
|
+
*
|
|
48989
|
+
* 여기서 끝나는 것은 턴이 아니라 세션이다 — 자식이 죽거나 우리가 접었을 때만 빠져나온다.
|
|
48990
|
+
*/
|
|
48991
|
+
async readSession(session) {
|
|
48992
|
+
try {
|
|
48993
|
+
for await (const message of session) {
|
|
48994
|
+
if (typeof message.session_id === "string" && message.session_id.length > 0) {
|
|
48995
|
+
this.latestSessionId = message.session_id;
|
|
48996
|
+
if (this.latestSessionId !== this.reportedSessionId) this.syncProviderSessionOnce();
|
|
48997
|
+
}
|
|
48998
|
+
this.rememberJobOutput(message);
|
|
48999
|
+
for (const event of chatEventsFromSdkMessage(message, { cwd: this.seed.cwd, toolNames: this.toolNames })) {
|
|
49000
|
+
this.ingest(event);
|
|
49001
|
+
}
|
|
49002
|
+
}
|
|
49003
|
+
} catch {
|
|
49004
|
+
if (!this.disposed) this.push({ kind: "error", code: "chat_session_lost" });
|
|
49005
|
+
} finally {
|
|
49006
|
+
this.retireSession(session);
|
|
49007
|
+
}
|
|
49008
|
+
}
|
|
49009
|
+
/**
|
|
49010
|
+
* 리더가 만든 이벤트 하나를 원장에 반영한다. 턴 경계도 여기서 결정된다.
|
|
49011
|
+
*
|
|
49012
|
+
* 스트림이 턴마다 끝나지 않으므로 경계는 내용이 말한다: `result`가 열린 턴을 닫고, 닫힌 뒤에
|
|
49013
|
+
* 다시 흐르기 시작한 내용이 새 턴을 연다. 후자가 백그라운드 작업이 끝나 자식이 모델을 다시
|
|
49014
|
+
* 깨운 자리이며, 그것을 앞 턴에 이어 붙이면 사용자가 읽은 답이 갈아치워진다.
|
|
49015
|
+
*/
|
|
49016
|
+
ingest(event) {
|
|
49017
|
+
if (event.kind === "turn-end") {
|
|
49018
|
+
const settling = this.settlingStoppedTurn;
|
|
49019
|
+
this.settlingStoppedTurn = false;
|
|
49020
|
+
if (this.turnOpen) {
|
|
49021
|
+
this.closeTurn({ ok: event.ok, ...event.durationMs === void 0 ? {} : { durationMs: event.durationMs }, ...event.answer === void 0 ? {} : { answer: event.answer } });
|
|
49022
|
+
} else if (settling) {
|
|
49023
|
+
this.releaseTurnCloseWaiters();
|
|
49024
|
+
}
|
|
49025
|
+
return;
|
|
49026
|
+
}
|
|
49027
|
+
if (!this.turnOpen && opensChatTurn(event)) this.openTurn({ dispatched: false });
|
|
49028
|
+
this.rememberTool(event);
|
|
49029
|
+
this.trackJob(event);
|
|
49030
|
+
if ((event.kind === "tool" || event.kind === "tool-start") && AGENT_CHAT_ASK_TOOLS.has(event.name)) return;
|
|
49031
|
+
if (event.kind === "text-delta" || event.kind === "tool-start") this.pushEphemeral(event);
|
|
49032
|
+
else this.push(event);
|
|
49033
|
+
}
|
|
49034
|
+
/** 살아 있는 잡의 집합을 이벤트대로 따라간다. `jobs`는 세는 것이 아니라 통째로 갈아 끼운다. */
|
|
49035
|
+
trackJob(event) {
|
|
49036
|
+
if (event.kind === "job") this.liveJobs.add(event.id);
|
|
49037
|
+
else if (event.kind === "job-end") this.liveJobs.delete(event.id);
|
|
49038
|
+
else if (event.kind === "jobs") {
|
|
49039
|
+
this.liveJobs.clear();
|
|
49040
|
+
for (const id of event.ids) this.liveJobs.add(id);
|
|
49041
|
+
}
|
|
49042
|
+
}
|
|
49043
|
+
/**
|
|
49044
|
+
* 턴 하나를 연다. 화면의 스피너와 활동축이 같은 순간에 켜지는 자리다.
|
|
49045
|
+
*
|
|
49046
|
+
* 이미 열려 있으면 다시 열지 않는다. 자식은 자기 큐를 갖고 있어 도는 중에도 메시지를 받는데
|
|
49047
|
+
* (백그라운드가 끝나 모델이 다시 깨어난 턴이 그 상태다), 그때 두 번째 `turn-start`를 세우면
|
|
49048
|
+
* 원장에 닫히지 않는 턴이 겹쳐 남는다 — 결말은 하나뿐이기 때문이다.
|
|
49049
|
+
*/
|
|
49050
|
+
openTurn(options) {
|
|
49051
|
+
if (this.turnOpen) return;
|
|
49052
|
+
this.turnOpen = true;
|
|
49053
|
+
this.turnReachedChild = !options.dispatched;
|
|
49054
|
+
this.push({ kind: "turn-start", at: Date.now() });
|
|
49055
|
+
if (!options.dispatched) this.seed.reportActivity(true);
|
|
49056
|
+
}
|
|
49057
|
+
/**
|
|
49058
|
+
* 열린 턴을 닫는다. 부르는 자리는 셋 — 자식의 `result`, 사용자의 중지, 세션의 소멸.
|
|
49059
|
+
*
|
|
49060
|
+
* 대기 중인 디스패치를 여기서 푼다. 그것이 풀려야 큐에 있던 다음 메시지가 시작하고, 풀리지
|
|
49061
|
+
* 않으면 세션은 조용히 멈춘 채 사용자의 다음 문장을 영영 받지 않는다.
|
|
49062
|
+
*/
|
|
49063
|
+
closeTurn(end) {
|
|
49064
|
+
if (!this.turnOpen) return;
|
|
49065
|
+
this.turnOpen = false;
|
|
49066
|
+
this.turnReachedChild = false;
|
|
49067
|
+
this.push({
|
|
49068
|
+
kind: "turn-end",
|
|
49069
|
+
ok: end.ok ?? end.stopped !== true,
|
|
49070
|
+
...end.stopped === true ? { stopped: true } : {},
|
|
49071
|
+
...end.durationMs === void 0 ? {} : { durationMs: end.durationMs },
|
|
49072
|
+
...end.answer === void 0 ? {} : { answer: end.answer }
|
|
49073
|
+
});
|
|
49074
|
+
this.abandonAsks("The turn ended before the question was answered.");
|
|
49075
|
+
this.seed.reportActivity(false);
|
|
49076
|
+
const awaiting = this.awaitingTurn;
|
|
49077
|
+
this.awaitingTurn = null;
|
|
49078
|
+
awaiting?.();
|
|
49079
|
+
this.releaseTurnCloseWaiters();
|
|
49080
|
+
}
|
|
49081
|
+
/** 자리가 비었음을 줄 서 있던 디스패치들에게 알린다. 결말 하나가 전부를 깨운다. */
|
|
49082
|
+
releaseTurnCloseWaiters() {
|
|
49083
|
+
if (this.turnCloseWaiters.size === 0) return;
|
|
49084
|
+
const waiters = [...this.turnCloseWaiters];
|
|
49085
|
+
this.turnCloseWaiters.clear();
|
|
49086
|
+
for (const wake of waiters) wake();
|
|
49087
|
+
}
|
|
49088
|
+
/**
|
|
49089
|
+
* 열린 턴이 닫힐 때까지 기다린다.
|
|
49090
|
+
*
|
|
49091
|
+
* 억제가 아니라 대기여야 하는 이유: 열린 턴에 그냥 올라타면 그 턴의 `result`가 이 디스패치를
|
|
49092
|
+
* 풀어 버린다. 사용자의 프롬프트는 아직 자식 안에서 도는데 원장은 끝났다고 말하고, 큐의 다음
|
|
49093
|
+
* 메시지가 그 위에서 조기에 시작한다.
|
|
49094
|
+
*/
|
|
49095
|
+
async awaitTurnClose() {
|
|
49096
|
+
if (!this.turnOpen && !this.settlingStoppedTurn) return;
|
|
49097
|
+
await new Promise((resolve3) => {
|
|
49098
|
+
this.turnCloseWaiters.add(resolve3);
|
|
49099
|
+
});
|
|
49100
|
+
}
|
|
49101
|
+
/**
|
|
49102
|
+
* 자식이 사라졌다. 열린 턴과 살아 있던 잡을 정직하게 닫고, 다음 디스패치가 새 자식을 세우도록
|
|
49103
|
+
* 자리를 비운다.
|
|
49104
|
+
*
|
|
49105
|
+
* 잡을 `stopped`로 닫는 이유: 그 작업들은 자식과 함께 사라졌다. 원장에 "도는 중"으로 남겨 두면
|
|
49106
|
+
* 화면은 오지 않을 결말을 기다리고, 그 조용한 거짓말이 이 원장이 고치려던 바로 그것이다.
|
|
49107
|
+
*/
|
|
49108
|
+
retireSession(session) {
|
|
49109
|
+
if (this.session === session) this.session = null;
|
|
49110
|
+
this.readerDone = null;
|
|
49111
|
+
try {
|
|
49112
|
+
session.close();
|
|
49113
|
+
} catch {
|
|
49114
|
+
}
|
|
49115
|
+
for (const id of [...this.liveJobs]) this.push({ kind: "job-end", id, status: "stopped" });
|
|
49116
|
+
this.liveJobs.clear();
|
|
49117
|
+
this.settlingStoppedTurn = false;
|
|
49118
|
+
this.closeTurn({ ok: false });
|
|
49119
|
+
this.releaseTurnCloseWaiters();
|
|
49120
|
+
}
|
|
49121
|
+
/**
|
|
49122
|
+
* 사용자의 메시지 하나를 자식에게 보내고 그 턴이 닫힐 때까지 기다린다.
|
|
49123
|
+
*
|
|
49124
|
+
* 기다리는 이유는 자식의 사정이 아니라 화면의 사정이다 — 자식은 자기 큐를 갖고 있어 턴 중에
|
|
49125
|
+
* 받아도 잃지 않지만, 원장은 턴 하나씩 그리므로 앞 턴이 닫힌 뒤 다음 디스패치를 세운다.
|
|
49126
|
+
*/
|
|
49127
|
+
async dispatch(text2) {
|
|
48552
49128
|
if (this.disposed) return;
|
|
48553
49129
|
const epoch = this.stopEpoch;
|
|
48554
49130
|
const stopped = () => epoch !== this.stopEpoch;
|
|
49131
|
+
await this.awaitTurnClose();
|
|
49132
|
+
if (this.disposed || stopped()) return;
|
|
48555
49133
|
this.push({ kind: "dispatch", text: text2, at: Date.now() });
|
|
48556
|
-
this.push({ kind: "turn-start", at: Date.now() });
|
|
48557
49134
|
if (!this.seed.reportActivity(true)) {
|
|
48558
49135
|
this.push({ kind: "error", code: "chat_activity_unavailable" });
|
|
48559
49136
|
this.push({ kind: "turn-end", ok: false });
|
|
48560
49137
|
return;
|
|
48561
49138
|
}
|
|
48562
|
-
|
|
49139
|
+
this.openTurn({ dispatched: true });
|
|
48563
49140
|
try {
|
|
48564
|
-
const
|
|
48565
|
-
const fleetMcpServers = await this.ensureFleetMcpServers().catch(() => {
|
|
48566
|
-
this.push({ kind: "error", code: "chat_fleet_tools_unavailable" });
|
|
48567
|
-
return [];
|
|
48568
|
-
});
|
|
48569
|
-
const run = await sdk.startTurn({
|
|
48570
|
-
prompt: text2,
|
|
48571
|
-
model: this.seed.model,
|
|
48572
|
-
...this.seed.effort ? { effort: this.seed.effort } : {},
|
|
48573
|
-
...this.seed.systemPrompt ? { systemPrompt: this.seed.systemPrompt } : {},
|
|
48574
|
-
...fleetMcpServers.length > 0 ? { servedMcpServers: fleetMcpServers } : {},
|
|
48575
|
-
cwd: this.seed.cwd,
|
|
48576
|
-
// 채팅으로 태어난 세션의 첫 턴에는 이어붙일 좌표가 없다 — resume 없이 시작하고,
|
|
48577
|
-
// SDK가 돌려주는 session_id가 그 자리를 채운다(그다음 턴부터는 resume이 선다).
|
|
48578
|
-
...this.latestSessionId ? { resume: this.latestSessionId } : {},
|
|
48579
|
-
permissionMode: "bypassPermissions",
|
|
48580
|
-
// 이 콜백은 권한 게이트가 아니다. 모드는 그대로 bypass이고 평범한 도구는 여기서 그냥
|
|
48581
|
-
// 통과한다 — 콜백을 주는 이유는 그래야 자식이 대화형 도구를 갖기 때문이다(실측: 29→32).
|
|
48582
|
-
canUseTool: (name, input, context) => this.askUser(name, input, context),
|
|
48583
|
-
// 스트리밍 감각의 근거 — 글자 단위 text_delta를 받으려면 부분 메시지가 필요하다.
|
|
48584
|
-
includePartialMessages: true
|
|
48585
|
-
});
|
|
49141
|
+
const session = await this.ensureSession();
|
|
48586
49142
|
if (stopped()) {
|
|
48587
|
-
|
|
48588
|
-
this.push({ kind: "turn-end", ok: false, stopped: true });
|
|
49143
|
+
this.closeTurn({ stopped: true });
|
|
48589
49144
|
return;
|
|
48590
49145
|
}
|
|
48591
|
-
this.
|
|
48592
|
-
|
|
48593
|
-
|
|
48594
|
-
for await (const message of run) {
|
|
48595
|
-
if (typeof message.session_id === "string" && message.session_id.length > 0) {
|
|
48596
|
-
this.latestSessionId = message.session_id;
|
|
48597
|
-
}
|
|
48598
|
-
this.rememberJobOutput(message);
|
|
48599
|
-
for (const event of chatEventsFromSdkMessage(message, { cwd: this.seed.cwd, toolNames: this.toolNames })) {
|
|
48600
|
-
if (event.kind === "turn-end") {
|
|
48601
|
-
turnClosed = true;
|
|
48602
|
-
} else if (turnClosed && opensChatTurn(event)) {
|
|
48603
|
-
this.push({ kind: "turn-start", at: Date.now() });
|
|
48604
|
-
turnClosed = false;
|
|
48605
|
-
}
|
|
48606
|
-
this.rememberTool(event);
|
|
48607
|
-
if ((event.kind === "tool" || event.kind === "tool-start") && AGENT_CHAT_ASK_TOOLS.has(event.name)) continue;
|
|
48608
|
-
if (event.kind === "text-delta" || event.kind === "tool-start") this.pushEphemeral(event);
|
|
48609
|
-
else this.push(event);
|
|
48610
|
-
}
|
|
48611
|
-
}
|
|
48612
|
-
} finally {
|
|
48613
|
-
this.activeRun = null;
|
|
48614
|
-
run.close();
|
|
48615
|
-
}
|
|
48616
|
-
if (!turnClosed) {
|
|
48617
|
-
if (stopped()) this.push({ kind: "turn-end", ok: false, stopped: true });
|
|
48618
|
-
else this.push({ kind: "turn-end", ok: true });
|
|
49146
|
+
if (this.session !== session) {
|
|
49147
|
+
this.closeTurn({ ok: false });
|
|
49148
|
+
return;
|
|
48619
49149
|
}
|
|
48620
|
-
|
|
49150
|
+
const settled = new Promise((resolve3) => {
|
|
49151
|
+
this.awaitingTurn = resolve3;
|
|
49152
|
+
});
|
|
49153
|
+
this.snapshotContextAtTurnStart(session);
|
|
49154
|
+
session.send(text2);
|
|
49155
|
+
this.turnReachedChild = true;
|
|
49156
|
+
await settled;
|
|
48621
49157
|
} catch {
|
|
48622
|
-
this.
|
|
48623
|
-
|
|
48624
|
-
if (!turnClosed) this.push({ kind: "turn-end", ok: false, stopped: true });
|
|
48625
|
-
await this.syncProviderSession().catch(() => void 0);
|
|
48626
|
-
} else {
|
|
49158
|
+
if (stopped()) this.closeTurn({ stopped: true });
|
|
49159
|
+
else {
|
|
48627
49160
|
this.push({ kind: "error", code: "chat_turn_failed" });
|
|
48628
|
-
|
|
49161
|
+
this.closeTurn({ ok: false });
|
|
48629
49162
|
}
|
|
48630
|
-
} finally {
|
|
48631
|
-
this.abandonAsks("The turn ended before the question was answered.");
|
|
48632
|
-
this.seed.reportActivity(false);
|
|
48633
49163
|
}
|
|
48634
49164
|
}
|
|
48635
49165
|
/**
|
|
@@ -48639,6 +49169,25 @@ var AgentChatSession = class {
|
|
|
48639
49169
|
* 좌표를 확정하는 것뿐이며, 세션 id가 바뀌지 않는 한 다시 할 일도 없다(resume이 새 id를 낳는
|
|
48640
49170
|
* 경우에만 다시 확정한다).
|
|
48641
49171
|
*/
|
|
49172
|
+
/**
|
|
49173
|
+
* 좌표 심기를 한 번에 하나만 날린다.
|
|
49174
|
+
*
|
|
49175
|
+
* 리더는 메시지마다 이 자리를 지난다. 첫 시도가 파일을 못 찾아 실패하는 것은 정상이므로
|
|
49176
|
+
* (자식이 아직 트랜스크립트를 만들지 않았다) 다음 메시지가 다시 시도해야 하는데, 가드가 없으면
|
|
49177
|
+
* 그 사이 도착한 메시지들이 같은 좌표를 겹쳐 심어 Operation write-back이 여러 번 인다.
|
|
49178
|
+
*/
|
|
49179
|
+
syncProviderSessionOnce() {
|
|
49180
|
+
if (this.syncFlight) {
|
|
49181
|
+
this.syncDirty = true;
|
|
49182
|
+
return;
|
|
49183
|
+
}
|
|
49184
|
+
this.syncDirty = false;
|
|
49185
|
+
this.syncFlight = this.syncProviderSession().catch(() => void 0).finally(() => {
|
|
49186
|
+
this.syncFlight = null;
|
|
49187
|
+
if (this.disposed || !this.syncDirty) return;
|
|
49188
|
+
if (this.latestSessionId !== this.reportedSessionId) this.syncProviderSessionOnce();
|
|
49189
|
+
});
|
|
49190
|
+
}
|
|
48642
49191
|
async syncProviderSession() {
|
|
48643
49192
|
const sessionId = this.latestSessionId;
|
|
48644
49193
|
if (!sessionId || sessionId === this.reportedSessionId) return;
|
|
@@ -49580,6 +50129,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
49580
50129
|
if (action === "chat-answer") return handleChatAnswer(req, res, sessionId);
|
|
49581
50130
|
if (action === "chat-stop") return handleChatStop(req, res, sessionId);
|
|
49582
50131
|
if (action === "chat-job") return handleChatJob(req, res, sessionId);
|
|
50132
|
+
if (action === "chat-job-stop") return handleChatJobStop(req, res, sessionId);
|
|
49583
50133
|
if (!ctx.host.security.isTerminalAuthorized(req)) {
|
|
49584
50134
|
ctx.host.http.writeJson(res, 401, { error: "unauthorized" });
|
|
49585
50135
|
return true;
|
|
@@ -50041,6 +50591,32 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
50041
50591
|
ctx.host.http.writeJson(res, 200, { ok: true });
|
|
50042
50592
|
return true;
|
|
50043
50593
|
}
|
|
50594
|
+
async function handleChatJobStop(req, res, sessionId) {
|
|
50595
|
+
if (req.method !== "POST") return methodNotAllowed2(res);
|
|
50596
|
+
if (!ctx.host.security.validateHost(req) || !ctx.host.security.isTerminalAuthorized(req)) return unauthorized(res);
|
|
50597
|
+
const node = ctx.host.operations.get(sessionId);
|
|
50598
|
+
if (!node || node.pluginId !== ctx.pluginId || node.type !== AGENT_OPERATION_TYPE) {
|
|
50599
|
+
ctx.host.http.writeJson(res, 404, { error: "session_not_found" });
|
|
50600
|
+
return true;
|
|
50601
|
+
}
|
|
50602
|
+
const chat = chatRegistry.get(sessionId);
|
|
50603
|
+
if (!chat) {
|
|
50604
|
+
ctx.host.http.writeJson(res, 409, { error: "chat_not_active" });
|
|
50605
|
+
return true;
|
|
50606
|
+
}
|
|
50607
|
+
const body = await ctx.host.http.readJsonBody(req);
|
|
50608
|
+
const jobId = typeof body?.jobId === "string" ? body.jobId : "";
|
|
50609
|
+
if (jobId.length === 0) {
|
|
50610
|
+
ctx.host.http.writeJson(res, 400, { error: "invalid_job_id" });
|
|
50611
|
+
return true;
|
|
50612
|
+
}
|
|
50613
|
+
if (!await chat.stopJob(jobId)) {
|
|
50614
|
+
ctx.host.http.writeJson(res, 409, { error: "job_stop_unavailable" });
|
|
50615
|
+
return true;
|
|
50616
|
+
}
|
|
50617
|
+
ctx.host.http.writeJson(res, 200, { ok: true });
|
|
50618
|
+
return true;
|
|
50619
|
+
}
|
|
50044
50620
|
async function handleChatJob(req, res, sessionId) {
|
|
50045
50621
|
if (req.method !== "GET") return methodNotAllowed2(res);
|
|
50046
50622
|
if (!ctx.host.security.validateHost(req) || !ctx.host.security.isTerminalAuthorized(req)) return unauthorized(res);
|
|
@@ -50096,7 +50672,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
50096
50672
|
const cwd = readPayloadString(node.payload, "cwd") || ctx.host.paths.resolveTheaterPath(node.theaterId);
|
|
50097
50673
|
if (!cwd) return { ok: false, status: 404, error: "theater_not_found" };
|
|
50098
50674
|
const model = readPayloadString(node.payload, "launchModel") || "opus[1m]";
|
|
50099
|
-
const
|
|
50675
|
+
const launchEffort = resolveChatLaunchEffort(readPayloadString(node.payload, "launchEffort"));
|
|
50100
50676
|
const claudeConfigDir = resolveClaudeConfigDir();
|
|
50101
50677
|
const gatewayBaseUrl = resolveAnalysisGatewayBaseUrl(origin);
|
|
50102
50678
|
try {
|
|
@@ -50117,7 +50693,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
50117
50693
|
seed: {
|
|
50118
50694
|
baseUrl: gatewayBaseUrl,
|
|
50119
50695
|
model,
|
|
50120
|
-
...
|
|
50696
|
+
...launchEffort ? { effort: launchEffort.effort } : {},
|
|
50121
50697
|
cwd,
|
|
50122
50698
|
claudeConfigDir,
|
|
50123
50699
|
origin: sessionOrigin,
|
|
@@ -50144,6 +50720,7 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
50144
50720
|
// 터미널이 `--settings`로 강제하는 것과 같은 값이다. 없으면 같은 프롬프트가 표면에
|
|
50145
50721
|
// 따라 다른 내장 스킬을 깨운다.
|
|
50146
50722
|
...chatSkillOverrides ? { skillOverrides: chatSkillOverrides } : {},
|
|
50723
|
+
...launchEffort?.ultracode ? { ultracode: true } : {},
|
|
50147
50724
|
// 터미널 런치와 같은 자리에 같은 옵션으로 렌더한다 — 두 표면이 한 플러그인을 공유한다.
|
|
50148
50725
|
resolveFleetPluginRoots: () => renderFleetPluginRootsForChat({
|
|
50149
50726
|
cwd,
|
|
@@ -50471,11 +51048,6 @@ async function createAgentApi(ctx, terminalRuntime, deps) {
|
|
|
50471
51048
|
return true;
|
|
50472
51049
|
}
|
|
50473
51050
|
}
|
|
50474
|
-
function chatEffortFromLaunchEffort(value) {
|
|
50475
|
-
if (value.length === 0) return void 0;
|
|
50476
|
-
if (value === "ultra") return "max";
|
|
50477
|
-
return ["low", "medium", "high", "xhigh", "max"].includes(value) ? value : void 0;
|
|
50478
|
-
}
|
|
50479
51051
|
function isOperationDeletedEventPayload(value) {
|
|
50480
51052
|
if (!value || typeof value !== "object") return false;
|
|
50481
51053
|
const event = value;
|