shennian 0.4.43 → 0.4.45
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/publish-build-manifest.json +91 -41
- package/dist/src/agents/adapter.d.ts +8 -0
- package/dist/src/agents/adapter.js +1 -1
- package/dist/src/agents/codex.d.ts +3 -1
- package/dist/src/agents/codex.js +10 -10
- package/dist/src/agents/pi-coding-agent.d.ts +3 -1
- package/dist/src/agents/pi-coding-agent.js +4 -4
- package/dist/src/commands/daemon-process.d.ts +2 -0
- package/dist/src/commands/daemon-process.js +1 -1
- package/dist/src/commands/daemon.d.ts +1 -1
- package/dist/src/commands/daemon.js +6 -6
- package/dist/src/commands/manager.js +1 -1
- package/dist/src/manager/prompt.d.ts +1 -1
- package/dist/src/manager/prompt.js +4 -3
- package/dist/src/manager/registry.d.ts +5 -3
- package/dist/src/manager/registry.js +1 -1
- package/dist/src/manager/runtime.d.ts +8 -16
- package/dist/src/manager/runtime.js +8 -20
- package/dist/src/manager/worker-ipc.d.ts +17 -0
- package/dist/src/manager/worker-ipc.js +1 -0
- package/dist/src/manager/worker-markdown.d.ts +10 -0
- package/dist/src/manager/worker-markdown.js +6 -0
- package/dist/src/native-fusion/codex-message-parser.d.ts +9 -0
- package/dist/src/native-fusion/codex-message-parser.js +1 -0
- package/dist/src/native-fusion/codex-parser.js +3 -3
- package/dist/src/native-fusion/service.d.ts +3 -0
- package/dist/src/native-fusion/service.js +2 -2
- package/dist/src/native-fusion/state.js +2 -2
- package/dist/src/native-fusion/types.d.ts +2 -0
- package/dist/src/room/room-action-client-types.d.ts +136 -0
- package/dist/src/room/room-action-client-types.js +1 -0
- package/dist/src/room/room-action-client.d.ts +3 -137
- package/dist/src/room/room-action-client.js +1 -1
- package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
- package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
- package/dist/src/session/handlers/chat-adapter-config.d.ts +11 -0
- package/dist/src/session/handlers/chat-adapter-config.js +1 -0
- package/dist/src/session/handlers/chat-events.d.ts +5 -0
- package/dist/src/session/handlers/chat-events.js +2 -0
- package/dist/src/session/handlers/chat-recovery.d.ts +4 -0
- package/dist/src/session/handlers/chat-recovery.js +1 -0
- package/dist/src/session/handlers/chat-session-lifecycle.d.ts +9 -0
- package/dist/src/session/handlers/chat-session-lifecycle.js +1 -0
- package/dist/src/session/handlers/chat.d.ts +1 -3
- package/dist/src/session/handlers/chat.js +1 -2
- package/dist/src/session/manager.d.ts +2 -1
- package/dist/src/session/manager.js +2 -2
- package/dist/src/session/queue-helpers.d.ts +4 -0
- package/dist/src/session/queue-helpers.js +8 -8
- package/dist/src/session/queue-storage.d.ts +7 -0
- package/dist/src/session/queue-storage.js +2 -0
- package/dist/src/session/queue.d.ts +14 -10
- package/dist/src/session/queue.js +1 -2
- package/dist/src/session/queued-chat-dispatch.d.ts +1 -0
- package/dist/src/session/queued-chat-dispatch.js +1 -1
- package/dist/src/session/run-recovery/schema.d.ts +3 -1
- package/dist/src/session/run-recovery/schema.js +1 -1
- package/dist/src/session/turn-trigger.d.ts +33 -0
- package/dist/src/session/turn-trigger.js +1 -0
- package/dist/src/session/types.d.ts +2 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/session.d.ts +12 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"jsMinified": true,
|
|
4
4
|
"minifier": "esbuild",
|
|
5
|
-
"fileCount":
|
|
5
|
+
"fileCount": 200,
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"file": "bin/shennian.js",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"file": "src/agents/adapter.js",
|
|
94
|
-
"beforeBytes":
|
|
95
|
-
"afterBytes":
|
|
94
|
+
"beforeBytes": 3707,
|
|
95
|
+
"afterBytes": 1948
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
"file": "src/agents/claude-managed-permissions.js",
|
|
@@ -121,8 +121,8 @@
|
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
"file": "src/agents/codex.js",
|
|
124
|
-
"beforeBytes":
|
|
125
|
-
"afterBytes":
|
|
124
|
+
"beforeBytes": 67113,
|
|
125
|
+
"afterBytes": 34450
|
|
126
126
|
},
|
|
127
127
|
{
|
|
128
128
|
"file": "src/agents/command-spec.js",
|
|
@@ -241,8 +241,8 @@
|
|
|
241
241
|
},
|
|
242
242
|
{
|
|
243
243
|
"file": "src/agents/pi-coding-agent.js",
|
|
244
|
-
"beforeBytes":
|
|
245
|
-
"afterBytes":
|
|
244
|
+
"beforeBytes": 25531,
|
|
245
|
+
"afterBytes": 13883
|
|
246
246
|
},
|
|
247
247
|
{
|
|
248
248
|
"file": "src/agents/pi-managed-extension.js",
|
|
@@ -296,8 +296,8 @@
|
|
|
296
296
|
},
|
|
297
297
|
{
|
|
298
298
|
"file": "src/commands/daemon-process.js",
|
|
299
|
-
"beforeBytes":
|
|
300
|
-
"afterBytes":
|
|
299
|
+
"beforeBytes": 5337,
|
|
300
|
+
"afterBytes": 2995
|
|
301
301
|
},
|
|
302
302
|
{
|
|
303
303
|
"file": "src/commands/daemon-start-wait.js",
|
|
@@ -311,8 +311,8 @@
|
|
|
311
311
|
},
|
|
312
312
|
{
|
|
313
313
|
"file": "src/commands/daemon.js",
|
|
314
|
-
"beforeBytes":
|
|
315
|
-
"afterBytes":
|
|
314
|
+
"beforeBytes": 45807,
|
|
315
|
+
"afterBytes": 21994
|
|
316
316
|
},
|
|
317
317
|
{
|
|
318
318
|
"file": "src/commands/integration.js",
|
|
@@ -326,8 +326,8 @@
|
|
|
326
326
|
},
|
|
327
327
|
{
|
|
328
328
|
"file": "src/commands/manager.js",
|
|
329
|
-
"beforeBytes":
|
|
330
|
-
"afterBytes":
|
|
329
|
+
"beforeBytes": 10029,
|
|
330
|
+
"afterBytes": 6444
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
"file": "src/commands/pair-authorization.js",
|
|
@@ -456,13 +456,13 @@
|
|
|
456
456
|
},
|
|
457
457
|
{
|
|
458
458
|
"file": "src/manager/prompt.js",
|
|
459
|
-
"beforeBytes":
|
|
460
|
-
"afterBytes":
|
|
459
|
+
"beforeBytes": 4582,
|
|
460
|
+
"afterBytes": 7519
|
|
461
461
|
},
|
|
462
462
|
{
|
|
463
463
|
"file": "src/manager/registry.js",
|
|
464
|
-
"beforeBytes":
|
|
465
|
-
"afterBytes":
|
|
464
|
+
"beforeBytes": 14080,
|
|
465
|
+
"afterBytes": 6882
|
|
466
466
|
},
|
|
467
467
|
{
|
|
468
468
|
"file": "src/manager/retired-external-channel-compat.js",
|
|
@@ -471,18 +471,33 @@
|
|
|
471
471
|
},
|
|
472
472
|
{
|
|
473
473
|
"file": "src/manager/runtime.js",
|
|
474
|
-
"beforeBytes":
|
|
475
|
-
"afterBytes":
|
|
474
|
+
"beforeBytes": 25164,
|
|
475
|
+
"afterBytes": 12805
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
"file": "src/manager/worker-ipc.js",
|
|
479
|
+
"beforeBytes": 10872,
|
|
480
|
+
"afterBytes": 5983
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"file": "src/manager/worker-markdown.js",
|
|
484
|
+
"beforeBytes": 1327,
|
|
485
|
+
"afterBytes": 884
|
|
476
486
|
},
|
|
477
487
|
{
|
|
478
488
|
"file": "src/native-fusion/codex-files.js",
|
|
479
489
|
"beforeBytes": 4582,
|
|
480
490
|
"afterBytes": 2163
|
|
481
491
|
},
|
|
492
|
+
{
|
|
493
|
+
"file": "src/native-fusion/codex-message-parser.js",
|
|
494
|
+
"beforeBytes": 4048,
|
|
495
|
+
"afterBytes": 1955
|
|
496
|
+
},
|
|
482
497
|
{
|
|
483
498
|
"file": "src/native-fusion/codex-parser.js",
|
|
484
|
-
"beforeBytes":
|
|
485
|
-
"afterBytes":
|
|
499
|
+
"beforeBytes": 26689,
|
|
500
|
+
"afterBytes": 10912
|
|
486
501
|
},
|
|
487
502
|
{
|
|
488
503
|
"file": "src/native-fusion/codex-user-input.js",
|
|
@@ -526,8 +541,8 @@
|
|
|
526
541
|
},
|
|
527
542
|
{
|
|
528
543
|
"file": "src/native-fusion/service.js",
|
|
529
|
-
"beforeBytes":
|
|
530
|
-
"afterBytes":
|
|
544
|
+
"beforeBytes": 37567,
|
|
545
|
+
"afterBytes": 16892
|
|
531
546
|
},
|
|
532
547
|
{
|
|
533
548
|
"file": "src/native-fusion/session-header.js",
|
|
@@ -536,8 +551,8 @@
|
|
|
536
551
|
},
|
|
537
552
|
{
|
|
538
553
|
"file": "src/native-fusion/state.js",
|
|
539
|
-
"beforeBytes":
|
|
540
|
-
"afterBytes":
|
|
554
|
+
"beforeBytes": 4401,
|
|
555
|
+
"afterBytes": 2293
|
|
541
556
|
},
|
|
542
557
|
{
|
|
543
558
|
"file": "src/native-fusion/types.js",
|
|
@@ -664,10 +679,15 @@
|
|
|
664
679
|
"beforeBytes": 1006,
|
|
665
680
|
"afterBytes": 462
|
|
666
681
|
},
|
|
682
|
+
{
|
|
683
|
+
"file": "src/room/room-action-client-types.js",
|
|
684
|
+
"beforeBytes": 329,
|
|
685
|
+
"afterBytes": 132
|
|
686
|
+
},
|
|
667
687
|
{
|
|
668
688
|
"file": "src/room/room-action-client.js",
|
|
669
|
-
"beforeBytes":
|
|
670
|
-
"afterBytes":
|
|
689
|
+
"beforeBytes": 29009,
|
|
690
|
+
"afterBytes": 14697
|
|
671
691
|
},
|
|
672
692
|
{
|
|
673
693
|
"file": "src/room/room-binding-client.js",
|
|
@@ -746,18 +766,38 @@
|
|
|
746
766
|
},
|
|
747
767
|
{
|
|
748
768
|
"file": "src/session/handlers/agent-workspace-validation.js",
|
|
749
|
-
"beforeBytes":
|
|
750
|
-
"afterBytes":
|
|
769
|
+
"beforeBytes": 9051,
|
|
770
|
+
"afterBytes": 4712
|
|
751
771
|
},
|
|
752
772
|
{
|
|
753
773
|
"file": "src/session/handlers/agents.js",
|
|
754
774
|
"beforeBytes": 2274,
|
|
755
775
|
"afterBytes": 1134
|
|
756
776
|
},
|
|
777
|
+
{
|
|
778
|
+
"file": "src/session/handlers/chat-adapter-config.js",
|
|
779
|
+
"beforeBytes": 2814,
|
|
780
|
+
"afterBytes": 1159
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
"file": "src/session/handlers/chat-events.js",
|
|
784
|
+
"beforeBytes": 15468,
|
|
785
|
+
"afterBytes": 6683
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
"file": "src/session/handlers/chat-recovery.js",
|
|
789
|
+
"beforeBytes": 6002,
|
|
790
|
+
"afterBytes": 3291
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
"file": "src/session/handlers/chat-session-lifecycle.js",
|
|
794
|
+
"beforeBytes": 3728,
|
|
795
|
+
"afterBytes": 1723
|
|
796
|
+
},
|
|
757
797
|
{
|
|
758
798
|
"file": "src/session/handlers/chat.js",
|
|
759
|
-
"beforeBytes":
|
|
760
|
-
"afterBytes":
|
|
799
|
+
"beforeBytes": 32547,
|
|
800
|
+
"afterBytes": 13978
|
|
761
801
|
},
|
|
762
802
|
{
|
|
763
803
|
"file": "src/session/handlers/control.js",
|
|
@@ -826,8 +866,8 @@
|
|
|
826
866
|
},
|
|
827
867
|
{
|
|
828
868
|
"file": "src/session/manager.js",
|
|
829
|
-
"beforeBytes":
|
|
830
|
-
"afterBytes":
|
|
869
|
+
"beforeBytes": 41802,
|
|
870
|
+
"afterBytes": 21965
|
|
831
871
|
},
|
|
832
872
|
{
|
|
833
873
|
"file": "src/session/native-cleanup-outbox.js",
|
|
@@ -851,23 +891,28 @@
|
|
|
851
891
|
},
|
|
852
892
|
{
|
|
853
893
|
"file": "src/session/queue-helpers.js",
|
|
854
|
-
"beforeBytes":
|
|
855
|
-
"afterBytes":
|
|
894
|
+
"beforeBytes": 7270,
|
|
895
|
+
"afterBytes": 3812
|
|
856
896
|
},
|
|
857
897
|
{
|
|
858
898
|
"file": "src/session/queue-retry.js",
|
|
859
899
|
"beforeBytes": 1253,
|
|
860
900
|
"afterBytes": 561
|
|
861
901
|
},
|
|
902
|
+
{
|
|
903
|
+
"file": "src/session/queue-storage.js",
|
|
904
|
+
"beforeBytes": 1663,
|
|
905
|
+
"afterBytes": 909
|
|
906
|
+
},
|
|
862
907
|
{
|
|
863
908
|
"file": "src/session/queue.js",
|
|
864
|
-
"beforeBytes":
|
|
865
|
-
"afterBytes":
|
|
909
|
+
"beforeBytes": 41605,
|
|
910
|
+
"afterBytes": 18836
|
|
866
911
|
},
|
|
867
912
|
{
|
|
868
913
|
"file": "src/session/queued-chat-dispatch.js",
|
|
869
|
-
"beforeBytes":
|
|
870
|
-
"afterBytes":
|
|
914
|
+
"beforeBytes": 2356,
|
|
915
|
+
"afterBytes": 1264
|
|
871
916
|
},
|
|
872
917
|
{
|
|
873
918
|
"file": "src/session/run-recovery/barrier.js",
|
|
@@ -886,8 +931,8 @@
|
|
|
886
931
|
},
|
|
887
932
|
{
|
|
888
933
|
"file": "src/session/run-recovery/schema.js",
|
|
889
|
-
"beforeBytes":
|
|
890
|
-
"afterBytes":
|
|
934
|
+
"beforeBytes": 6647,
|
|
935
|
+
"afterBytes": 4272
|
|
891
936
|
},
|
|
892
937
|
{
|
|
893
938
|
"file": "src/session/store.js",
|
|
@@ -899,6 +944,11 @@
|
|
|
899
944
|
"beforeBytes": 2886,
|
|
900
945
|
"afterBytes": 1429
|
|
901
946
|
},
|
|
947
|
+
{
|
|
948
|
+
"file": "src/session/turn-trigger.js",
|
|
949
|
+
"beforeBytes": 106,
|
|
950
|
+
"afterBytes": 1
|
|
951
|
+
},
|
|
902
952
|
{
|
|
903
953
|
"file": "src/session/types.js",
|
|
904
954
|
"beforeBytes": 159,
|
|
@@ -52,6 +52,11 @@ export type AgentSendContext = {
|
|
|
52
52
|
/** Marks internal recovery input; it must never be persisted as user-authored text. */
|
|
53
53
|
recovery?: 'upgrade';
|
|
54
54
|
};
|
|
55
|
+
export type AgentActiveInput = {
|
|
56
|
+
text: string;
|
|
57
|
+
attachments?: ChatAttachmentMeta[];
|
|
58
|
+
clientMessageId?: string;
|
|
59
|
+
};
|
|
55
60
|
export type ImportedAgentMessage = {
|
|
56
61
|
/** Stable within repeated imports of the same provider session. */
|
|
57
62
|
sourceId: string;
|
|
@@ -122,6 +127,9 @@ export declare abstract class AgentAdapter extends EventEmitter<AgentAdapterEven
|
|
|
122
127
|
abstract readonly type: AgentType;
|
|
123
128
|
/** Explicit fail-closed default; resumable adapters must opt in. */
|
|
124
129
|
get recoveryCapabilities(): AgentRecoveryCapabilities;
|
|
130
|
+
/** Explicit fail-closed capability for adding input to the current provider turn. */
|
|
131
|
+
get supportsActiveInput(): boolean;
|
|
132
|
+
injectActiveInput?(input: AgentActiveInput): Promise<void>;
|
|
125
133
|
configure?(options: {
|
|
126
134
|
sessionId?: string;
|
|
127
135
|
externalChannel?: ExternalChannelSessionStatus | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventEmitter as o}from"node:events";import{RECOVERY_CONTINUE_TEXT as u}from"../session/run-recovery/schema.js";class l extends o{get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!1}}async inspectInterruptedRun(e){if(!this.getStatus)return{state:"interrupted",providerRunId:e.providerRunId};const r=await this.getStatus().catch(()=>null);return r?.active?{state:"active",providerRunId:r.runId??e.providerRunId,runPhase:r.runPhase}:{state:"interrupted",providerRunId:e.providerRunId}}async recoverInterruptedRun(e){const r=await this.inspectInterruptedRun(e);if(r.state==="terminal"&&this.recoveryCapabilities.inspectTerminal)return{result:"terminal_reconciled"};if(r.state==="active"&&this.recoveryCapabilities.reattachRun)return{result:"reattached"};if(!e.agentSessionId)return{result:"interrupted_by_upgrade",reason:"missing_agent_session"};if(!this.recoveryCapabilities.resumeSession)return{result:"interrupted_by_upgrade",reason:"resume_unsupported"};if(e.continueDispatchState!=="none")return{result:"recovery_failed",reason:"continue_dispatch_outcome_unknown"};try{return e.beforeContinueDispatch?.(),await this.send(u,e.modelId??void 0,e.reasoningEffort??void 0,void 0,e.systemPrompt,e.sendContext),{result:"continued"}}catch(i){const a=i instanceof Error?i.message:String(i),n=a.toLowerCase();return{result:"recovery_failed",reason:n.includes("auth")||n.includes("login")?"authentication_required":n.includes("permission")||n.includes("capability")?"permission_context_unavailable":n.includes("session")&&n.includes("not")?"provider_session_missing":"provider_error",message:a.slice(0,500)}}}}const s=new Map;function p(t,e){s.set(t,e)}function f(t){s.delete(t)}function g(t){const e=s.get(t);return e?e():null}function m(){return[...s.keys()]}export{l as AgentAdapter,g as createAgent,m as getRegisteredAgents,p as registerAgent,f as unregisterAgent};
|
|
1
|
+
import{EventEmitter as o}from"node:events";import{RECOVERY_CONTINUE_TEXT as u}from"../session/run-recovery/schema.js";class l extends o{get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!1}}get supportsActiveInput(){return!1}async inspectInterruptedRun(e){if(!this.getStatus)return{state:"interrupted",providerRunId:e.providerRunId};const r=await this.getStatus().catch(()=>null);return r?.active?{state:"active",providerRunId:r.runId??e.providerRunId,runPhase:r.runPhase}:{state:"interrupted",providerRunId:e.providerRunId}}async recoverInterruptedRun(e){const r=await this.inspectInterruptedRun(e);if(r.state==="terminal"&&this.recoveryCapabilities.inspectTerminal)return{result:"terminal_reconciled"};if(r.state==="active"&&this.recoveryCapabilities.reattachRun)return{result:"reattached"};if(!e.agentSessionId)return{result:"interrupted_by_upgrade",reason:"missing_agent_session"};if(!this.recoveryCapabilities.resumeSession)return{result:"interrupted_by_upgrade",reason:"resume_unsupported"};if(e.continueDispatchState!=="none")return{result:"recovery_failed",reason:"continue_dispatch_outcome_unknown"};try{return e.beforeContinueDispatch?.(),await this.send(u,e.modelId??void 0,e.reasoningEffort??void 0,void 0,e.systemPrompt,e.sendContext),{result:"continued"}}catch(i){const a=i instanceof Error?i.message:String(i),n=a.toLowerCase();return{result:"recovery_failed",reason:n.includes("auth")||n.includes("login")?"authentication_required":n.includes("permission")||n.includes("capability")?"permission_context_unavailable":n.includes("session")&&n.includes("not")?"provider_session_missing":"provider_error",message:a.slice(0,500)}}}}const s=new Map;function p(t,e){s.set(t,e)}function f(t){s.delete(t)}function g(t){const e=s.get(t);return e?e():null}function m(){return[...s.keys()]}export{l as AgentAdapter,g as createAgent,m as getRegisteredAgents,p as registerAgent,f as unregisterAgent};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AgentAdapter, type AgentSendContext, type AgentSendResult, type AgentStartOptions } from './adapter.js';
|
|
1
|
+
import { AgentAdapter, type AgentActiveInput, type AgentSendContext, type AgentSendResult, type AgentStartOptions } from './adapter.js';
|
|
2
2
|
import { type ChatAttachmentMeta, type ExternalChannelSessionStatus } from '@shennian/wire';
|
|
3
3
|
import type { SessionRunPhase } from '@shennian/wire';
|
|
4
4
|
import { type CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
|
|
@@ -19,6 +19,8 @@ export declare function buildCodexQueuedText(text: string, attachments?: ChatAtt
|
|
|
19
19
|
export declare function buildCodexQueueArgs(threadId: string, text: string, attachments?: ChatAttachmentMeta[]): string[];
|
|
20
20
|
export declare class CodexAdapter extends AgentAdapter {
|
|
21
21
|
private readonly options;
|
|
22
|
+
get supportsActiveInput(): boolean;
|
|
23
|
+
injectActiveInput(input: AgentActiveInput): Promise<void>;
|
|
22
24
|
readonly type: "codex";
|
|
23
25
|
get recoveryCapabilities(): {
|
|
24
26
|
inspectTerminal: boolean;
|
package/dist/src/agents/codex.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import{spawnSync as
|
|
2
|
-
`)}function ge(o,e){const t=e?.filter(s=>s.path&&!/^https?:\/\//i.test(s.path)&&!o.includes(s.path));if(!t?.length)return o;const r=t.map((s,i)=>{const n=
|
|
3
|
-
`)}function fe(o,e,t){return["queue","--thread",o,"--message",ge(e,t)]}function
|
|
4
|
-
${l}`.trim();if(u!==0){m(new Error(f||`codex queue exited with code ${u??"unknown"}`));return}const b=f.match(/Queued message\s+([^\s]+)\s+for thread/i)?.[1];m(void 0,b)})})}async resume(e){await this.killProcess(),this.agentSessionId=e,this.resetTextState()}async setTitle(e,t,r){const s=e.trim(),i=t.replace(/\s+/g," ").trim();!s||!i||(this.agentSessionId=s,r?.trim()&&(this.workDir=r),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:s,name:i}))}async stop(){this.managedRoomTools.deactivateTurn(),await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let r=null;try{r=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const s=r?.type==="active"||!!t;return{active:s,runId:t,runPhase:s?this.mapThreadStatusToRunPhase(r):null,canStop:!!(s&&t&&this.process)}}spawnCodex(e){const t=T("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const r=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=r,S({input:r.stdout}).on("line",n=>{if(n.trim())try{const a=JSON.parse(n);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:n})}});let i="";r.stderr?.on("data",n=>{i+=n.toString()}),r.on("close",n=>{this.process===r&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),r.on("error",n=>{this.process===r&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=T("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],r=this.options.modelInstructionsFile??U(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);r&&t.push("-c",`model_instructions_file=${JSON.stringify(r)}`);const s=x(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});this.process=s,this.stderrBuf="",this.appServerStartupError=null,S({input:s.stdout}).on("line",n=>{if(!n.trim())return;let a;try{a=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(a)}),s.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),s.on("close",n=>{if(this.process!==s)return;const a=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(new Error(k(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&a&&this.handleProcessClose(n,this.stderrBuf)}),s.on("error",n=>{this.process===s&&(this.process=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=I(e);await this.sendRpc("initialize",{clientInfo:K,capabilities:{experimentalApi:!0}}),this.managedPermissionConfig=this.managedAgentPolicy&&!R(this.managedAgentPolicy)?await this.buildManagedPermissionConfig():null;const r=!!(this.configuredManagedRoomContextToken||this.configuredManagedRoomExecutor);if(this.managedAgentPolicy&&r&&!this.managedRoomTools.isConfigured()&&(this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),!this.managedRoomTools.isConfigured()))throw new Error("codex_managed_room_tool_context_unavailable");if(this.agentSessionId&&this.managedAgentPolicy&&r&&this.agentSessionId!==this.managedRoomToolThreadId){if(!this.managedRoomTools.isConfigured())throw new Error("codex_managed_room_tool_context_unavailable");this.agentSessionId=null}if(this.agentSessionId){const c={threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},persistExtendedHistory:!0,...t?{model:t}:{}};let l;try{l=await this.sendRpc("thread/resume",{...c,excludeTurns:!0})}catch(p){if(!de(p))throw p;l=await this.sendRpc("thread/resume",c)}this.agentSessionId=l.thread?.id??this.agentSessionId,this.managedPermissionConfig&&E(l,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(this.agentSessionId),this.managedRoomToolThreadId=this.agentSessionId);return}const s=this.options.hidden||this.nativeSessionVisibility==="internal"||!this.persistNativeSession,i=s?void 0:await this.resolveCodexProjectId(),n={cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},serviceName:"Shennian",...s?{}:{threadSource:"user"},experimentalRawEvents:!1,persistExtendedHistory:!0,...this.managedAgentPolicy&&r?{dynamicTools:G}:{},...i?{projectId:i}:{},...t?{model:t}:{}};let a;if(s&&!this.managedPermissionConfig)a=await this.sendRpc("thread/start",n);else try{a=await this.sendRpc("thread/start",{...n,historyMode:"paginated"})}catch(c){throw ae(c)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5728 Codex Desktop \u4E2D\u7EE7\u7EED\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u964D\u7EA7\u521B\u5EFA\u4E0D\u53EF\u89C1\u7684 legacy \u4F1A\u8BDD\u3002",{cause:c}):c}const d=a.thread?.id;if(!d)throw new Error("codex app-server thread/start returned no thread id");this.managedPermissionConfig&&E(a,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(d),this.managedRoomToolThreadId=d),this.agentSessionId=d}async buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)throw new Error("managed_agent_policy_missing");const t=e.adapterPolicy.externalCapabilities.mcp?[]:X(await this.sendRpc("config/read",{cwd:e.adapterPolicy.workDir}));return H(z(e),e.adapterPolicy.workDir,{configuredMcpServerNames:t,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}async resolveCodexProjectId(){const e=this.workDir?.trim();if(e)try{const t=[];let r;do{const c=await this.sendRpc("project/list",{limit:100,...r?{cursor:r}:{}});t.push(...c.data??[]),r=c.nextCursor}while(r);const s=ce(t,e);if(s)return s;const i=g.resolve(e),n=`shennian-project-${w("sha256").update(i).digest("hex")}`,d=(await this.sendRpc("project/create",{idempotencyKey:n,name:g.basename(i)||i,roots:[{path:i}],metadata:{createdBy:"Shennian"}})).project?.id;if(!d)throw new Error("codex app-server project/create returned no project id");return d}catch(t){throw le(t)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5F52\u5C5E\u5230 Codex Desktop \u9879\u76EE\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u76F4\u63A5\u4FEE\u6539 Codex Desktop \u7684\u79C1\u6709\u4FA7\u680F\u7D22\u5F15\u3002",{cause:t}):t}}async startTurnWithRecovery(e,t,r,s,i){try{return await this.startTurn(e,t,r,s,i)}catch(n){if(!v(n))throw n;if(this.managedAgentPolicy||this.managedPermissionConfig){this.logManagedThreadLifecycle("rollout.missing",{threadId:e,recovery:"recreate"}),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(r);const a=this.agentSessionId;if(!a)throw new Error("codex app-server did not recreate the managed thread",{cause:n});return this.logManagedThreadLifecycle("thread.recreated",{previousThreadId:e,threadId:a}),this.emitEvent({state:"start",agentSessionId:a}),await this.startFreshManagedTurnWithReadinessRetry(a,t,r,s,i)}return await this.killProcess(),await this.ensureAppServer(r),await this.startTurn(e,t,r,s,i)}}async startFreshManagedTurnWithReadinessRetry(e,t,r,s,i){const n=[0,100,300,1e3];let a;for(let d=0;d<n.length;d+=1){const c=n[d];c>0&&await new Promise(l=>setTimeout(l,c));try{const l=await this.startTurn(e,t,r,s,i);return d>0&&this.logManagedThreadLifecycle("rollout.ready",{threadId:e,attempt:d+1}),l}catch(l){if(a=l,!v(l)||d===n.length-1)throw l;this.logManagedThreadLifecycle("rollout.retry",{threadId:e,attempt:d+2,delayMs:n[d+1]})}}throw a}logManagedThreadLifecycle(e,t){console.error(`[codex.managed] ${JSON.stringify({event:e,...t})}`)}async startTurn(e,t,r,s,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[ue(t,i)],approvalPolicy:"never",...this.managedPermissionConfig?{}:{sandboxPolicy:{type:"dangerFullAccess"}},...r?{model:r}:{},...s?{effort:s}:{}})}catch(n){throw s&&ee(n)?new Error(`Codex app-server does not accept reasoning effort "${s}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),!(!e||!t||!this.process)&&await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3)}sendRpc(e,t,r=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const s=this.process;if(!s?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((a,d)=>{const c=setTimeout(()=>{this.pendingRequests.delete(i),d(new Error(`codex app-server request timed out: ${e}`))},r);this.pendingRequests.set(i,{resolve:a,reject:d,timer:c}),s.stdin.write(`${n}
|
|
5
|
-
`,l=>{l&&(clearTimeout(c),this.pendingRequests.delete(i),d(l))})})}handleAppServerMessage(e){if(e.method==="item/tool/call"&&e.id!=null){this.handleManagedRoomToolCall(e.id,e.params??{});return}if(e.id!=null){const r=typeof e.id=="number"?this.pendingRequests.get(e.id):void 0;r&&(clearTimeout(r.timer),this.pendingRequests.delete(e.id),e.error?r.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):r.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null,i=typeof t.threadId=="string"?t.threadId:"";s&&(this.activeTurnId=s,this.managedRoomToolThreadId===i&&!this.managedRoomTools.bindTurn(i,s)&&this.emitErrorIfOpen("codex_managed_room_turn_binding_failed"));break}case"thread/status/changed":{const r=typeof t.threadId=="string"?t.threadId:"";if(r&&this.agentSessionId&&r!==this.agentSessionId)break;const s=typeof t.status=="object"&&t.status!==null?t.status:null;s?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(s)});break}case"item/agentMessage/delta":{const r=typeof t.itemId=="string"?t.itemId:"";r&&this.deltaItemIds.add(r),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null;(!this.activeTurnId||s===this.activeTurnId)&&(this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),this.emitFinalIfOpen());break}case"turn/failed":{const r=_(t);if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r||"turn failed");break}case"error":{const r=_(t);if(
|
|
6
|
-
`)}mapThreadStatusToRunPhase(e){const t=e?.type==="active"&&Array.isArray(e.activeFlags)?e.activeFlags:[];return t.includes("waitingOnApproval")?"waiting_approval":t.includes("waitingOnUserInput")?"waiting_user_input":"thinking"}handleAppServerNonJsonStdout(e){const t=
|
|
7
|
-
(exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const r=typeof t.tool=="string"?t.tool:t.type;if(y(r))return;const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:r,args:s}),this.emitEvent({state:"tool-result",name:r,result:A(t.error??t.result??t.contentItems??"")});break}case"fileChange":break;case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,r=typeof t?.last=="object"&&t.last!==null?t.last:null,s=typeof t?.total=="object"&&t.total!==null?t.total:null,i=r??s;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,a=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||a!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:a??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!
|
|
1
|
+
import{spawnSync as q}from"node:child_process";import{createInterface as w}from"node:readline";import{createHash as S,randomUUID as N}from"node:crypto";import g from"node:path";import{AgentAdapter as D,registerAgent as L}from"./adapter.js";import{resolveBuiltinCommand as T,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as F,buildManagedAgentProcessEnv as $,buildManagedNativeFullProcessEnv as U}from"../agent-env.js";import{ensurePlatformInstructionsFile as W}from"./platform-instructions.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as C}from"@shennian/wire";import{isCodexThreadTailInterrupted as z}from"../native-fusion/codex-files.js";import{resolveManagedAgentAdapterEnforcement as B,isManagedAgentNativeFull as R}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as G}from"../security/managed-agent-runtime.js";import{CODEX_MANAGED_ROOM_DYNAMIC_TOOLS as J,CodexManagedRoomToolBinding as V}from"./codex-managed-room-tools.js";import{assertCodexManagedPermissionProfile as E,CODEX_MANAGED_RUNTIME_SECURITY as H,compileCodexManagedPermissions as X,extractCodexMcpServerNames as K}from"./codex-managed-permissions.js";import{CODEX_APP_SERVER_CLIENT_INFO as Q,extractAppServerErrorMessage as _,formatCodexErrorMessage as j,formatTransientCodexStatus as Y,isCodexCollabAgentItem as Z,isCodexCollabAgentToolName as y,isCodexLegacyCollabAgentItem as ee,isCodexUnsupportedEffortError as te,isMissingCodexRolloutError as v,isTransientCodexErrorMessage as re,looksLikeCodexInteractiveAuthPrompt as se,looksLikeFatalCodexStderr as ne,normalizeCodexModelId as I,normalizeCodexReasoningEffort as ie,normalizeCodexStderr as k,normalizeTerminalText as oe,safeStringify as A,stripGitDirectiveArtifacts as ae}from"./codex-utils.js";import{isCodexUnsupportedEffortError as Ne,isMissingCodexRolloutError as De,normalizeCodexModelId as Le,normalizeCodexReasoningEffort as Fe}from"./codex-utils.js";G("codex",H);function P(o){const e=o instanceof Error?o.message:String(o);return/already has an active writer|thread-store conflict/i.test(e)}function de(o){const e=o instanceof Error?o.message:String(o);return/paginated(?:_threads|\s+(?:thread\s+)?history)?.*(?:not supported|unsupported|unavailable)/i.test(e)||/(?:not supported|unsupported|unavailable).*paginated(?:_threads|\s+(?:thread\s+)?history)?/i.test(e)}function le(o){const e=o instanceof Error?o.message:String(o);return/unknown field [`'"]?excludeTurns/i.test(e)||/excludeTurns.*(?:not supported|unsupported|unavailable)/i.test(e)}function ce(o){const e=o instanceof Error?o.message:String(o);return/(?:method not found|unknown method).*(?:project\/list|project\/create)/i.test(e)||/(?:project\/list|project\/create).*(?:not supported|unsupported|unavailable)/i.test(e)}function ue(o,e){const t=g.resolve(e);let r;for(const s of o)if(s.id)for(const i of s.roots??[]){if(!i.path)continue;const n=g.resolve(i.path),a=g.relative(n,t);!(a===""||!a.startsWith("..")&&!g.isAbsolute(a))||n.length<=(r?.rootLength??-1)||(r={id:s.id,rootLength:n.length})}return r?.id}function M(o,e){const t=e?.flatMap(s=>he(s)).filter(s=>!/^https?:\/\//i.test(s.path)).filter(s=>s.path);return{type:"text",text:me(o,e),text_elements:[],...t?.length?{local_images:t}:{}}}function he(o){if(o.kind==="image")return o.previewData?[{path:o.path,data:o.previewData,mimeType:o.mimeType}]:[{path:o.path}];if(o.mimeType.startsWith("video/")){const e=pe(o.path);return e?[{path:e}]:[]}return[]}function pe(o){if(!o||/^https?:\/\//i.test(o))return null;const e=g.extname(o),r=`${e?o.slice(0,-e.length):o}.preview.png`;return q("ffmpeg",["-y","-ss","0","-i",o,"-frames:v","1","-vf","scale=320:-1",r],{stdio:"ignore",timeout:15e3}).status===0?r:null}function me(o,e){const t=e?.filter(i=>i.kind!=="image").filter(i=>i.path&&!/^https?:\/\//i.test(i.path));if(!t?.length||t.every(i=>o.includes(i.path)))return o;const s=t.map((i,n)=>{const a=i.name||`attachment-${n+1}`,d=i.mimeType?` (${i.mimeType})`:"";return`[${b(a)}${d}](<${i.path}>)`});return[o,"",...s].join(`
|
|
2
|
+
`)}function ge(o,e){const t=e?.filter(s=>s.path&&!/^https?:\/\//i.test(s.path)&&!o.includes(s.path));if(!t?.length)return o;const r=t.map((s,i)=>{const n=b(s.name||`attachment-${i+1}`);return s.kind==="image"?``:`[${n}](<${s.path}>)`});return[o,"",...r].join(`
|
|
3
|
+
`)}function fe(o,e,t){return["queue","--thread",o,"--message",ge(e,t)]}function b(o){return o.replace(/[[\]\\]/g,"\\$&")}class ye extends D{options;get supportsActiveInput(){return!0}async injectActiveInput(e){const t=this.agentSessionId,r=this.activeTurnId;if(!t||!r||!this.process)throw new Error("codex_active_turn_unavailable");const s=await this.sendRpc("turn/steer",{threadId:t,expectedTurnId:r,input:[M(e.text,e.attachments)],...e.clientMessageId?{clientUserMessageId:e.clientMessageId}:{}});if(s.turnId&&s.turnId!==r)throw new Error("codex_active_turn_changed")}type="codex";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;workDir=null;seq=0;runId="";pendingUsage;agentSessionId=null;hasEmittedText=!1;textTail="";terminalState="open";forceCloseTimer=null;stderrBuf="";rpcSeq=1;pendingRequests=new Map;appServerReady=null;appServerStartupError=null;activeTurnId=null;deltaItemIds=new Set;lastTransientStatus="";agentSystemPrompt="";managedAgentPolicy=null;managedPermissionConfig=null;configurationRestartRequired=!1;managedRoomTools=new V;configuredManagedRoomContextToken=null;configuredManagedRoomExecutor=null;managedRoomToolThreadId=null;preparedExternalOwnerThreadId=null;managedTurnReplay=null;managedAsyncRecovery=null;persistNativeSession=!0;nativeSessionVisibility="user";constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){const t=this.configurationFingerprint();this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),("managedRoomContextToken"in e||"managedRoomExecutor"in e)&&(this.managedRoomTools.deactivateTurn(),this.configuredManagedRoomContextToken=e.managedRoomContextToken?.trim()||null,this.configuredManagedRoomExecutor=e.managedRoomExecutor??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir);const r=this.configurationFingerprint();t!==r&&this.process&&(this.configurationRestartRequired=!0)}configurationFingerprint(){const e=Object.keys(this.extraEnv).sort().map(t=>[t,this.extraEnv[t]??null]);return S("sha256").update(JSON.stringify({sessionId:this.shennianSessionId,externalChannel:this.externalChannel,env:e,managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}buildProcessEnv(e={}){if(!this.managedAgentPolicy)return F({...e,...this.extraEnv});if(R(this.managedAgentPolicy))return U({...e,...this.extraEnv});const t=Object.fromEntries(Object.entries(this.extraEnv).filter(([r])=>r!=="SHENNIAN_MANAGED_ROOM_CONTEXT"&&r!=="SHENNIAN_MANAGED_ROOM_IPC_ROOT"));return $({agentType:"codex",providerEnv:t,sessionEnv:t,runtimeEnv:e})}async start(e,t,r,s){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=s?.persistNativeSession!==!1,this.nativeSessionVisibility=s?.nativeSessionVisibility??"user",r&&(this.agentSessionId=r)}async prepareSend(e,t,r,s,i,n){const a=i?.trim()??"";if(a!==this.agentSystemPrompt&&(this.agentSystemPrompt=a,this.process&&await this.killProcess(!0)),!(!this.agentSessionId||this.activeTurnId)){this.preparedExternalOwnerThreadId=null;try{await this.ensureAppServer(I(t))}catch(d){if(!P(d))throw d;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:d});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:d});this.preparedExternalOwnerThreadId=this.agentSessionId}}}async send(e,t,r,s,i,n){if(n?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(n?.source==="room_activation"&&(!this.configuredManagedRoomContextToken||!this.configuredManagedRoomExecutor))throw new Error("codex_managed_room_tool_context_unavailable");this.activeTurnId&&(await this.interruptActiveTurn().catch(()=>{}),await this.killProcess(!0)),this.configurationRestartRequired&&this.process&&await this.killProcess(!0),this.configurationRestartRequired=!1;const a=I(t),d=ie(r),c=i?.trim()??"";if(c!==this.agentSystemPrompt&&(this.agentSystemPrompt=c,this.process&&await this.killProcess(!0)),n?.source==="room_activation"&&this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),this.runId=N(),this.seq=0,this.resetRunState(),this.agentSessionId&&this.preparedExternalOwnerThreadId===this.agentSessionId)return this.preparedExternalOwnerThreadId=null,{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)};try{await this.ensureAppServer(a)}catch(h){if(!this.agentSessionId||!P(h))throw h;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:h});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:h});return{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)}}const l=this.agentSessionId;if(!l)throw new Error("codex app-server did not create a thread");this.emitEvent({state:"start",agentSessionId:l}),this.managedTurnReplay=this.managedPermissionConfig?{text:e,modelId:a,reasoningEffort:d,attachments:s,recoveryCount:0}:null;const p=await this.startTurnWithRecovery(l,e,a,d,s),m=this.agentSessionId??l;if(this.activeTurnId=p.turn?.id??null,this.managedRoomToolThreadId===m&&this.activeTurnId&&!this.managedRoomTools.bindTurn(m,this.activeTurnId))throw await this.killProcess(),new Error("codex_managed_room_turn_binding_failed");return{deliveryMode:"direct"}}isThreadTailInterrupted(e){return this.options.isThreadTailInterrupted?.(e)??z(e)}async enqueueForExternalOwner(e,t,r){const s=T("codex");if(!s)throw new Error('Command "codex" not found. Is OpenAI Codex CLI installed?');const i=fe(e,t,r),n=x(s,i,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});return await new Promise((a,d)=>{let c="",l="",p=!1;const m=(u,f)=>{p||(p=!0,clearTimeout(h),u?d(u):a(f))},h=setTimeout(()=>{n.kill("SIGTERM"),m(new Error("Codex Desktop message queue timed out"))},6e4);h.unref?.(),n.stdout?.on("data",u=>{c+=u.toString()}),n.stderr?.on("data",u=>{l+=u.toString()}),n.once("error",u=>m(u)),n.once("close",u=>{const f=`${c}
|
|
4
|
+
${l}`.trim();if(u!==0){m(new Error(f||`codex queue exited with code ${u??"unknown"}`));return}const O=f.match(/Queued message\s+([^\s]+)\s+for thread/i)?.[1];m(void 0,O)})})}async resume(e){await this.killProcess(),this.agentSessionId=e,this.resetTextState()}async setTitle(e,t,r){const s=e.trim(),i=t.replace(/\s+/g," ").trim();!s||!i||(this.agentSessionId=s,r?.trim()&&(this.workDir=r),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:s,name:i}))}async stop(){this.managedRoomTools.deactivateTurn(),await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let r=null;try{r=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const s=r?.type==="active"||!!t;return{active:s,runId:t,runPhase:s?this.mapThreadStatusToRunPhase(r):null,canStop:!!(s&&t&&this.process)}}spawnCodex(e){const t=T("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const r=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=r,w({input:r.stdout}).on("line",n=>{if(n.trim())try{const a=JSON.parse(n);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:n})}});let i="";r.stderr?.on("data",n=>{i+=n.toString()}),r.on("close",n=>{this.process===r&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),r.on("error",n=>{this.process===r&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=T("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],r=this.options.modelInstructionsFile??W(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);r&&t.push("-c",`model_instructions_file=${JSON.stringify(r)}`);const s=x(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});this.process=s,this.stderrBuf="",this.appServerStartupError=null,w({input:s.stdout}).on("line",n=>{if(!n.trim())return;let a;try{a=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(a)}),s.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),s.on("close",n=>{if(this.process!==s)return;const a=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(new Error(k(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&a&&this.handleProcessClose(n,this.stderrBuf)}),s.on("error",n=>{this.process===s&&(this.process=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=I(e);await this.sendRpc("initialize",{clientInfo:Q,capabilities:{experimentalApi:!0}}),this.managedPermissionConfig=this.managedAgentPolicy&&!R(this.managedAgentPolicy)?await this.buildManagedPermissionConfig():null;const r=!!(this.configuredManagedRoomContextToken||this.configuredManagedRoomExecutor);if(this.managedAgentPolicy&&r&&!this.managedRoomTools.isConfigured()&&(this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),!this.managedRoomTools.isConfigured()))throw new Error("codex_managed_room_tool_context_unavailable");if(this.agentSessionId&&this.managedAgentPolicy&&r&&this.agentSessionId!==this.managedRoomToolThreadId){if(!this.managedRoomTools.isConfigured())throw new Error("codex_managed_room_tool_context_unavailable");this.agentSessionId=null}if(this.agentSessionId){const c={threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},persistExtendedHistory:!0,...t?{model:t}:{}};let l;try{l=await this.sendRpc("thread/resume",{...c,excludeTurns:!0})}catch(p){if(!le(p))throw p;l=await this.sendRpc("thread/resume",c)}this.agentSessionId=l.thread?.id??this.agentSessionId,this.managedPermissionConfig&&E(l,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(this.agentSessionId),this.managedRoomToolThreadId=this.agentSessionId);return}const s=this.options.hidden||this.nativeSessionVisibility==="internal"||!this.persistNativeSession,i=s?void 0:await this.resolveCodexProjectId(),n={cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},serviceName:"Shennian",...s?{}:{threadSource:"user"},experimentalRawEvents:!1,persistExtendedHistory:!0,...this.managedAgentPolicy&&r?{dynamicTools:J}:{},...i?{projectId:i}:{},...t?{model:t}:{}};let a;if(s&&!this.managedPermissionConfig)a=await this.sendRpc("thread/start",n);else try{a=await this.sendRpc("thread/start",{...n,historyMode:"paginated"})}catch(c){throw de(c)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5728 Codex Desktop \u4E2D\u7EE7\u7EED\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u964D\u7EA7\u521B\u5EFA\u4E0D\u53EF\u89C1\u7684 legacy \u4F1A\u8BDD\u3002",{cause:c}):c}const d=a.thread?.id;if(!d)throw new Error("codex app-server thread/start returned no thread id");this.managedPermissionConfig&&E(a,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(d),this.managedRoomToolThreadId=d),this.agentSessionId=d}async buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)throw new Error("managed_agent_policy_missing");const t=e.adapterPolicy.externalCapabilities.mcp?[]:K(await this.sendRpc("config/read",{cwd:e.adapterPolicy.workDir}));return X(B(e),e.adapterPolicy.workDir,{configuredMcpServerNames:t,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}async resolveCodexProjectId(){const e=this.workDir?.trim();if(e)try{const t=[];let r;do{const c=await this.sendRpc("project/list",{limit:100,...r?{cursor:r}:{}});t.push(...c.data??[]),r=c.nextCursor}while(r);const s=ue(t,e);if(s)return s;const i=g.resolve(e),n=`shennian-project-${S("sha256").update(i).digest("hex")}`,d=(await this.sendRpc("project/create",{idempotencyKey:n,name:g.basename(i)||i,roots:[{path:i}],metadata:{createdBy:"Shennian"}})).project?.id;if(!d)throw new Error("codex app-server project/create returned no project id");return d}catch(t){throw ce(t)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5F52\u5C5E\u5230 Codex Desktop \u9879\u76EE\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u76F4\u63A5\u4FEE\u6539 Codex Desktop \u7684\u79C1\u6709\u4FA7\u680F\u7D22\u5F15\u3002",{cause:t}):t}}async startTurnWithRecovery(e,t,r,s,i){try{return await this.startTurn(e,t,r,s,i)}catch(n){if(!v(n))throw n;if(this.managedAgentPolicy||this.managedPermissionConfig){this.logManagedThreadLifecycle("rollout.missing",{threadId:e,recovery:"recreate"}),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(r);const a=this.agentSessionId;if(!a)throw new Error("codex app-server did not recreate the managed thread",{cause:n});return this.logManagedThreadLifecycle("thread.recreated",{previousThreadId:e,threadId:a}),this.emitEvent({state:"start",agentSessionId:a}),await this.startFreshManagedTurnWithReadinessRetry(a,t,r,s,i)}return await this.killProcess(),await this.ensureAppServer(r),await this.startTurn(e,t,r,s,i)}}async startFreshManagedTurnWithReadinessRetry(e,t,r,s,i){const n=[0,100,300,1e3];let a;for(let d=0;d<n.length;d+=1){const c=n[d];c>0&&await new Promise(l=>setTimeout(l,c));try{const l=await this.startTurn(e,t,r,s,i);return d>0&&this.logManagedThreadLifecycle("rollout.ready",{threadId:e,attempt:d+1}),l}catch(l){if(a=l,!v(l)||d===n.length-1)throw l;this.logManagedThreadLifecycle("rollout.retry",{threadId:e,attempt:d+2,delayMs:n[d+1]})}}throw a}logManagedThreadLifecycle(e,t){console.error(`[codex.managed] ${JSON.stringify({event:e,...t})}`)}async startTurn(e,t,r,s,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[M(t,i)],approvalPolicy:"never",...this.managedPermissionConfig?{}:{sandboxPolicy:{type:"dangerFullAccess"}},...r?{model:r}:{},...s?{effort:s}:{}})}catch(n){throw s&&te(n)?new Error(`Codex app-server does not accept reasoning effort "${s}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),!(!e||!t||!this.process)&&await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3)}sendRpc(e,t,r=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const s=this.process;if(!s?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((a,d)=>{const c=setTimeout(()=>{this.pendingRequests.delete(i),d(new Error(`codex app-server request timed out: ${e}`))},r);this.pendingRequests.set(i,{resolve:a,reject:d,timer:c}),s.stdin.write(`${n}
|
|
5
|
+
`,l=>{l&&(clearTimeout(c),this.pendingRequests.delete(i),d(l))})})}handleAppServerMessage(e){if(e.method==="item/tool/call"&&e.id!=null){this.handleManagedRoomToolCall(e.id,e.params??{});return}if(e.id!=null){const r=typeof e.id=="number"?this.pendingRequests.get(e.id):void 0;r&&(clearTimeout(r.timer),this.pendingRequests.delete(e.id),e.error?r.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):r.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null,i=typeof t.threadId=="string"?t.threadId:"";s&&(this.activeTurnId=s,this.managedRoomToolThreadId===i&&!this.managedRoomTools.bindTurn(i,s)&&this.emitErrorIfOpen("codex_managed_room_turn_binding_failed"));break}case"thread/status/changed":{const r=typeof t.threadId=="string"?t.threadId:"";if(r&&this.agentSessionId&&r!==this.agentSessionId)break;const s=typeof t.status=="object"&&t.status!==null?t.status:null;s?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(s)});break}case"item/agentMessage/delta":{const r=typeof t.itemId=="string"?t.itemId:"";r&&this.deltaItemIds.add(r),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null;(!this.activeTurnId||s===this.activeTurnId)&&(this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),this.emitFinalIfOpen());break}case"turn/failed":{const r=_(t);if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r||"turn failed");break}case"error":{const r=_(t);if(re(r)){this.emitTransientStatus(r);return}if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r);break}}}scheduleManagedAsyncRolloutRecovery(e){if(!this.managedAgentPolicy&&!this.managedPermissionConfig||!this.managedTurnReplay||!v(new Error(e)))return!1;if(this.managedAsyncRecovery)return!0;if(this.managedTurnReplay.recoveryCount>=2)return!1;this.managedTurnReplay.recoveryCount+=1;const t=this.managedTurnReplay.recoveryCount;return this.logManagedThreadLifecycle("rollout.failed-async",{threadId:this.agentSessionId,recoveryCount:t}),this.managedAsyncRecovery=this.recoverManagedTurnAfterAsyncRolloutFailure().catch(r=>{const s=v(r)?"no rollout found after managed thread recovery":r instanceof Error?r.message:"managed thread recovery failed";this.emitErrorIfOpen(s)}).finally(()=>{this.managedAsyncRecovery=null}),!0}async recoverManagedTurnAfterAsyncRolloutFailure(){const e=this.managedTurnReplay,t=this.agentSessionId;if(!e||!t||this.terminalState!=="open")return;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(e.modelId);const r=this.agentSessionId;if(!r)throw new Error("codex app-server did not recreate the managed thread");this.logManagedThreadLifecycle("thread.recreated-async",{previousThreadId:t,threadId:r,recoveryCount:e.recoveryCount}),this.emitEvent({state:"start",agentSessionId:r});const s=await this.startFreshManagedTurnWithReadinessRetry(r,e.text,e.modelId,e.reasoningEffort,e.attachments);if(this.activeTurnId=s.turn?.id??null,this.managedRoomToolThreadId===r&&this.activeTurnId&&!this.managedRoomTools.bindTurn(r,this.activeTurnId))throw new Error("codex_managed_room_turn_binding_failed")}async handleManagedRoomToolCall(e,t){const r=await this.managedRoomTools.execute(t);if(this.writeAppServerResponse(e,r),r.success&&t.tool==="shennian_room_send"){const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:null,i=typeof s?.text=="string"?s.text.trim():"";i&&this.emitText(i,"block")}}writeAppServerResponse(e,t){const r=this.process;r?.stdin&&r.stdin.write(`${JSON.stringify({id:e,result:t})}
|
|
6
|
+
`)}mapThreadStatusToRunPhase(e){const t=e?.type==="active"&&Array.isArray(e.activeFlags)?e.activeFlags:[];return t.includes("waitingOnApproval")?"waiting_approval":t.includes("waitingOnUserInput")?"waiting_user_input":"thinking"}handleAppServerNonJsonStdout(e){const t=oe(e);se(t)&&this.failAppServerStartup(new Error("Codex \u672A\u767B\u5F55\u3002\u8BF7\u5148\u5728\u8FD9\u53F0\u7535\u8111\u7684\u7EC8\u7AEF\u8FD0\u884C `codex`\uFF0C\u6309\u63D0\u793A\u5B8C\u6210 ChatGPT \u767B\u5F55\u6216\u914D\u7F6E API key\uFF0C\u7136\u540E\u518D\u56DE\u5230\u795E\u5FF5\u53D1\u9001\u6D88\u606F\u3002"))}failAppServerStartup(e){this.appServerStartupError||(this.appServerStartupError=e,this.rejectAllPending(e),this.process?.kill("SIGTERM"))}handleAppServerCompletedItem(e){const t=typeof e.item=="object"&&e.item!==null?e.item:null;if(!(!t||typeof t.type!="string")&&!Z(t))switch(t.type){case"agentMessage":{const r=typeof t.id=="string"?t.id:"";if(r&&this.deltaItemIds.has(r))return;typeof t.text=="string"&&this.emitText(t.text,"block");break}case"commandExecution":{const r=typeof t.command=="string"?t.command:"",s=typeof t.aggregatedOutput=="string"?t.aggregatedOutput:"";r&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:r}}),this.emitEvent({state:"tool-result",name:"command_execution",result:[s,t.exitCode!=null?`
|
|
7
|
+
(exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const r=typeof t.tool=="string"?t.tool:t.type;if(y(r))return;const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:r,args:s}),this.emitEvent({state:"tool-result",name:r,result:A(t.error??t.result??t.contentItems??"")});break}case"fileChange":break;case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,r=typeof t?.last=="object"&&t.last!==null?t.last:null,s=typeof t?.total=="object"&&t.total!==null?t.total:null,i=r??s;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,a=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||a!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:a??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!ee(t))switch(t.type){case"agent_message":case"reasoning":{e.type==="item.completed"&&t.text&&this.emitText(t.text,"block");break}case"command_execution":{if(e.type==="item.started"&&t.command&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:t.command}}),e.type==="item.completed"){const r=[t.aggregated_output??"",t.exit_code!=null?`
|
|
8
8
|
(exit ${t.exit_code})`:""];this.emitEvent({state:"tool-result",name:"command_execution",result:r.join("").trim()||String(t.status??"")})}break}case"mcp_tool_call":{if(t.tool&&y(t.tool))return;if(e.type==="item.started"&&this.emitEvent({state:"tool-call",name:t.tool??"mcp_tool",args:{server:t.server,...t.arguments&&typeof t.arguments=="object"?t.arguments:{}}}),e.type==="item.completed"){const r=t.error&&typeof t.error=="object"?t.error.message:void 0;this.emitEvent({state:"tool-result",name:t.tool??"mcp_tool",result:r??A(t.result)})}break}case"file_change":break;case"web_search":{e.type==="item.completed"&&t.query&&this.emitText(`[web_search] ${t.query}`,"block");break}case"todo_list":{if(e.type==="item.completed"&&t.items?.length){const r=t.items.map(s=>`- [${s.completed?"x":" "}] ${s.text}`).join(`
|
|
9
|
-
`);this.emitText(r,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const s=e.usage;if(s){const i=s.input_tokens??s.prompt_tokens,n=s.output_tokens??s.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const s=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(s);return}case"error":{const s=typeof e.message=="string"?e.message:"";if(s.includes("Reconnecting"))return;this.emitErrorIfOpen(s||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const s=e.thread_id??e.session_id??e.id;typeof s=="string"&&s&&(this.agentSessionId=s,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const s=e.content??e.text;s&&this.emitText(s);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&y(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&y(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",r=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",s=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:r,content:s,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(e=!1){const t=this.process;if(this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),e||this.clearConfiguredManagedRoomContext(),!t){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),t.kill("SIGTERM"),await new Promise(r=>{t.on("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,r]of this.pendingRequests.entries())clearTimeout(r.timer),r.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const r=k(t);if(e!==0&&e!==null){const s=r||`codex exited with code ${e}`;this.emitErrorIfOpen(s)}else
|
|
10
|
-
`,thinking:!0}))}resetTextState(){this.hasEmittedText=!1,this.textTail=""}emitText(e,t="delta"){if(!e)return;let r=
|
|
9
|
+
`);this.emitText(r,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const s=e.usage;if(s){const i=s.input_tokens??s.prompt_tokens,n=s.output_tokens??s.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const s=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(s);return}case"error":{const s=typeof e.message=="string"?e.message:"";if(s.includes("Reconnecting"))return;this.emitErrorIfOpen(s||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const s=e.thread_id??e.session_id??e.id;typeof s=="string"&&s&&(this.agentSessionId=s,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const s=e.content??e.text;s&&this.emitText(s);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&y(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&y(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",r=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",s=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:r,content:s,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(e=!1){const t=this.process;if(this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),e||this.clearConfiguredManagedRoomContext(),!t){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),t.kill("SIGTERM"),await new Promise(r=>{t.on("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,r]of this.pendingRequests.entries())clearTimeout(r.timer),r.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const r=k(t);if(e!==0&&e!==null){const s=r||`codex exited with code ${e}`;this.emitErrorIfOpen(s)}else ne(r)?this.emitErrorIfOpen(r):this.emitFinalIfOpen();this.pendingUsage=void 0}emitFinalIfOpen(){this.terminalState==="open"&&(this.terminalState="final",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"final",usage:this.pendingUsage,agentSessionId:this.agentSessionId??void 0}),this.killProcess().catch(()=>{}))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"error",message:j(e)}),this.scheduleProcessClose())}resetRunState(){this.pendingUsage=void 0,this.terminalState="open",this.deltaItemIds.clear(),this.lastTransientStatus="",this.clearForceCloseTimer(),this.resetTextState()}clearConfiguredManagedRoomContext(){this.configuredManagedRoomContextToken=null,this.configuredManagedRoomExecutor=null}emitTransientStatus(e){const t=Y(e);!t||t===this.lastTransientStatus||this.terminalState!=="open"||(this.lastTransientStatus=t,this.emitEvent({state:"delta",text:`${t}
|
|
10
|
+
`,thinking:!0}))}resetTextState(){this.hasEmittedText=!1,this.textTail=""}emitText(e,t="delta"){if(!e)return;let r=ae(e);r&&(t==="block"&&this.hasEmittedText&&!r.startsWith(`
|
|
11
11
|
`)&&(this.textTail.endsWith(`
|
|
12
12
|
`)?r=`
|
|
13
13
|
${r}`:this.textTail.endsWith(`
|
|
14
14
|
|
|
15
15
|
`)||(r=`
|
|
16
16
|
|
|
17
|
-
${r}`)),this.hasEmittedText=!0,this.textTail=(this.textTail+r).slice(-4),this.emitEvent({state:"delta",text:r}))}scheduleProcessClose(){const e=this.process;!e||this.forceCloseTimer||(this.forceCloseTimer=setTimeout(()=>{this.forceCloseTimer=null,this.process===e&&(e.kill("SIGTERM"),setTimeout(()=>{this.process===e&&e.kill("SIGKILL")},1e3))},250))}clearForceCloseTimer(){this.forceCloseTimer&&(clearTimeout(this.forceCloseTimer),this.forceCloseTimer=null)}}
|
|
17
|
+
${r}`)),this.hasEmittedText=!0,this.textTail=(this.textTail+r).slice(-4),this.emitEvent({state:"delta",text:r}))}scheduleProcessClose(){const e=this.process;!e||this.forceCloseTimer||(this.forceCloseTimer=setTimeout(()=>{this.forceCloseTimer=null,this.process===e&&(e.kill("SIGTERM"),setTimeout(()=>{this.process===e&&e.kill("SIGKILL")},1e3))},250))}clearForceCloseTimer(){this.forceCloseTimer&&(clearTimeout(this.forceCloseTimer),this.forceCloseTimer=null)}}L("codex",()=>new ye);export{ye as CodexAdapter,fe as buildCodexQueueArgs,ge as buildCodexQueuedText,P as isCodexActiveWriterError,le as isCodexExcludeTurnsUnsupportedError,de as isCodexPaginatedHistoryUnsupportedError,ce as isCodexProjectApiUnsupportedError,Ne as isCodexUnsupportedEffortError,De as isMissingCodexRolloutError,Le as normalizeCodexModelId,Fe as normalizeCodexReasoningEffort,ue as selectCodexProjectIdForWorkDir};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
|
|
2
|
-
import { AgentAdapter, type AgentSendContext } from './adapter.js';
|
|
2
|
+
import { AgentAdapter, type AgentActiveInput, type AgentSendContext } from './adapter.js';
|
|
3
3
|
import { type CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
|
|
4
4
|
export declare class PiCodingAgentAdapter extends AgentAdapter {
|
|
5
5
|
readonly type: "pi-coding-agent";
|
|
6
|
+
get supportsActiveInput(): boolean;
|
|
7
|
+
injectActiveInput(input: AgentActiveInput): Promise<void>;
|
|
6
8
|
get recoveryCapabilities(): {
|
|
7
9
|
inspectTerminal: boolean;
|
|
8
10
|
reattachRun: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import h from"node:fs";import u from"node:path";import{randomUUID as
|
|
2
|
-
[truncated]`}function
|
|
3
|
-
`)}`}function K(i,t){const s=[];for(const e of i??[]){if(e.kind!=="image"||!e.mimeType.startsWith("image/"))continue;let n=e.previewData?.trim()??"";const a=n.indexOf(",");if(n.startsWith("data:")&&a>=0&&(n=n.slice(a+1)),!n&&t&&e.path&&!/^https?:\/\//i.test(e.path))try{const l=h.statSync(e.path);l.isFile()&&l.size<=10*1024*1024&&(n=h.readFileSync(e.path).toString("base64"))}catch{n=""}n&&s.push({type:"image",data:n,mimeType:e.mimeType})}return s}class W extends E{type="pi-coding-agent";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;modelBroker=null;persistNativeSession=!0;validationRoot=null;runPhase=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,s,e,n){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.agentSessionId=e??null;const a=f("runtime","pi-coding-agent",g(t));this.persistNativeSession=n?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:u.join(a,`validation-${P()}`),this.sessionDir=this.validationRoot?u.join(this.validationRoot,"sessions"):u.join(a,"sessions"),h.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&h.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,s,e,n,a,l){await this.ensureProcess(a);const c=this.requireRpc(),p=await this.readState(),o=!!(p.isStreaming||p.isCompacting);(!o||!this.runId)&&(this.runId=P(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const d=L(s);if(d.modelId&&!o&&(p.model?.id!==d.modelId||d.provider&&p.model?.provider!==d.provider)){if(!d.provider)throw new Error("Pi model selection must include provider/modelId");await c.request("set_model",{provider:d.provider,modelId:d.modelId})}e&&!o&&await c.request("set_thinking_level",{level:e});const r=o?l?.source==="room_activation"?"follow_up":"steer":"prompt",m={message:Z(t,n,this.workDir,this.externalChannel,this.shennianSessionId,null)},S=K(n,!this.managedAgentPolicy);S.length&&!this.modelBroker&&(m.images=S),this.modelBroker?.setTurnActive(!0);try{await c.request(r,m)}catch(_){throw this.modelBroker?.setTurnActive(!1),_}}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&this.emitTerminal({state:"aborted"}),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),s=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:s,runId:s?this.runId:null,runPhase:s?this.runPhase??"thinking":null,canStop:s}}async setTitle(t,s){this.rpc&&await this.rpc.request("set_session_name",{name:s.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc)return;const s=A("pi-coding-agent");if(!s)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const e=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];this.agentSessionId&&e.push("--session",this.agentSessionId);const n=await this.prepareHostedModel();if(n&&e.push("--provider","shennian-dashscope","--model","deepseek-v4-flash-0731"),this.managedAgentPolicy&&!w(this.managedAgentPolicy)){e.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const r=this.managedTools(),m=j({outputPath:u.join(f("runtime","pi-coding-agent",g(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});e.push("--no-builtin-tools","--extension",m),r.length?e.push("--tools",r.join(",")):e.push("--no-tools")}const a=M(this.workDir,this.externalChannel,this.shennianSessionId,t),l=this.validationRoot??f("runtime","pi-coding-agent",g(this.shennianSessionId));h.mkdirSync(l,{recursive:!0,mode:448}),this.promptFile=u.join(l,"instructions.md"),h.writeFileSync(this.promptFile,a,{encoding:"utf8",mode:384}),process.platform!=="win32"&&h.chmodSync(this.promptFile,384),e.push("--append-system-prompt",this.promptFile);const c={NO_COLOR:"1",...n?{PI_CODING_AGENT_DIR:n.configDir}:{}},p=this.managedAgentPolicy&&!w(this.managedAgentPolicy)?R({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:c}):this.managedAgentPolicy?T({...c,...this.extraEnv}):x({...c,...this.extraEnv});let o;try{o=k(s,e,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:p})}catch(r){throw await this.stopModelBroker(),r}this.process=o,this.stderr="",o.stderr?.on("data",r=>{const m=typeof r=="string"?r:r.toString("utf8");this.stderr=y(`${this.stderr}${m}`,F)});const d=new C(o);this.rpc=d,d.on("event",r=>this.handleRpcEvent(r)),d.on("protocolError",r=>this.emitError(r.message)),o.once("close",r=>{this.process===o&&(this.process=null,this.rpc=null,this.terminal||this.emitError(r===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${r??"unknown"}${this.stderr?`: ${this.stderr}`:""}`),this.stopModelBroker())}),o.once("error",r=>{this.process===o&&this.emitError(r.message)});try{const r=await this.readState();if(!r.sessionId)throw new Error("Pi RPC did not return a session ID");if(r.isStreaming||r.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&r.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!r.sessionFile||!this.ownsSessionFile(r.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=r.sessionId,this.persistNativeSession&&q(r.sessionId,this.sessionDir)}catch(r){throw await this.stopProcess(),r}}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const s=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&s.push("edit","write");const e=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,n=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(e||n||t.fileAccess==="host-full")&&s.push("bash"),s}ownsSessionFile(t){const s=u.resolve(this.sessionDir),e=u.resolve(t),n=u.relative(s,e);return n!==""&&!n.startsWith("..")&&!u.isAbsolute(n)}async readState(){const t=await this.requireRpc().request("get_state");return G(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=I(t.usage)??this.lastUsage;const s=t.assistantMessageEvent;if(!s||typeof s!="object")return;const e=s;e.type==="text_delta"&&typeof e.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:e.delta})):e.type==="thinking_delta"&&typeof e.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:e.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:z(t.result)||X(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const s=t.message;if(s&&typeof s=="object"){const e=s;this.lastUsage=I(e.usage)??this.lastUsage,e.stopReason==="error"&&(this.modelBroker?.setTurnActive(!1),this.emitError(typeof e.errorMessage=="string"?e.errorMessage:"Pi model request failed"))}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.modelBroker?.setTurnActive(!1),this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}emitError(t){this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"error",message:H(t)})}async prepareHostedModel(){const t=N(),s=t.machineToken?.trim();if(!s)return null;const e=new O({serverUrl:t.serverUrl?.trim()||"https://shennian.net",machineToken:s,sessionId:this.shennianSessionId}),n=await e.start(),a=this.validationRoot?u.join(this.validationRoot,"agent-config"):f("runtime","pi-coding-agent",g(this.shennianSessionId),"agent-config");h.mkdirSync(a,{recursive:!0,mode:448}),process.platform!=="win32"&&h.chmodSync(a,448);const l=u.join(a,"models.json"),c={providers:{"shennian-dashscope":{baseUrl:n.baseUrl,api:"openai-completions",apiKey:n.apiKey,authHeader:!0,compat:{supportsDeveloperRole:!1,supportsReasoningEffort:!0},models:[{id:"deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",reasoning:!0,input:["text"],thinkingLevelMap:{off:null,minimal:null,low:"low",medium:null,high:"high",xhigh:null,max:"max"}}]}}};return h.writeFileSync(l,`${JSON.stringify(c,null,2)}
|
|
4
|
-
`,{encoding:"utf8",mode:384}),process.platform!=="win32"&&h.chmodSync(l,384),this.modelBroker=e,{configDir:a}}async stopModelBroker(){const t=this.modelBroker;this.modelBroker=null,await t?.stop().catch(()=>{})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t?(t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const
|
|
1
|
+
import h from"node:fs";import u from"node:path";import{randomUUID as w}from"node:crypto";import{AgentAdapter as A,registerAgent as k}from"./adapter.js";import{resolveBuiltinCommand as x,spawnAgentCommand as R}from"./command-spec.js";import{buildAgentProcessEnv as T,buildManagedAgentProcessEnv as N,buildManagedNativeFullProcessEnv as b}from"../agent-env.js";import{loadConfig as M,resolveShennianPath as f}from"../config/index.js";import{buildInlineChannelPreamble as C,buildPlatformInstructions as D}from"./platform-instructions.js";import{isManagedAgentNativeFull as P}from"../security/managed-agent-policy.js";import{PiRpcClient as B}from"./pi-rpc-client.js";import{registerManagedAgentRuntimeSecurity as O}from"../security/managed-agent-runtime.js";import{PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY as j}from"./pi-coding-agent-managed-permissions.js";import{PiManagedModelBroker as q}from"./pi-managed-model-broker.js";import{writePiManagedExtension as F}from"./pi-managed-extension.js";import{recordPiSessionOwnership as U}from"./pi-session-ownership.js";O("pi-coding-agent",j);const $=32*1024,G=256*1024,z=3e3;function g(n){return n.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,180)||"session"}function H(n){return n.data&&typeof n.data=="object"&&!Array.isArray(n.data)?n.data:{}}function X(n){if(typeof n=="string")return n;if(!n||typeof n!="object")return"";const t=n.content;return Array.isArray(t)?t.map(s=>{if(!s||typeof s!="object")return"";const e=s;return e.type==="text"&&typeof e.text=="string"?e.text:""}).join(""):""}function y(n,t=G){return n.length<=t?n:`${n.slice(0,t)}
|
|
2
|
+
[truncated]`}function L(n){return y(n,2e3).replace(/Bearer\s+[A-Za-z0-9._~-]+/gi,"Bearer [redacted]").replace(/\b(?:pimc|mrc)_[A-Za-z0-9_-]{20,}\b/g,"[redacted-capability]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g,"[redacted-key]")}function Z(n){try{return y(JSON.stringify(n))}catch{return"[unserializable]"}}function I(n){if(!n||typeof n!="object")return;const t=n;if(!(typeof t.input!="number"&&typeof t.output!="number"))return{inputTokens:typeof t.input=="number"?t.input:0,outputTokens:typeof t.output=="number"?t.output:0}}function K(n){const t=n?.trim();if(!t)return{};const s=t.indexOf("/");return s<=0||s===t.length-1?{modelId:t}:{provider:t.slice(0,s),modelId:t.slice(s+1)}}function _(n,t,s,e,i,a){const l=C(s,e,i,a),c=t?.filter(o=>o.kind!=="image")??[];if(!c.length)return`${l}${n}`;const p=c.map(o=>`[${o.name}](<${o.path}>)`);return`${l}${[n,"",...p].join(`
|
|
3
|
+
`)}`}function E(n,t){const s=[];for(const e of n??[]){if(e.kind!=="image"||!e.mimeType.startsWith("image/"))continue;let i=e.previewData?.trim()??"";const a=i.indexOf(",");if(i.startsWith("data:")&&a>=0&&(i=i.slice(a+1)),!i&&t&&e.path&&!/^https?:\/\//i.test(e.path))try{const l=h.statSync(e.path);l.isFile()&&l.size<=10*1024*1024&&(i=h.readFileSync(e.path).toString("base64"))}catch{i=""}i&&s.push({type:"image",data:i,mimeType:e.mimeType})}return s}class W extends A{type="pi-coding-agent";get supportsActiveInput(){return!0}async injectActiveInput(t){const s=await this.readState();if(!this.rpc||!this.runId||!s.isStreaming&&!s.isCompacting)throw new Error("pi_active_turn_unavailable");const e={message:_(t.text,t.attachments,this.workDir,this.externalChannel,this.shennianSessionId,null)},i=E(t.attachments,!this.managedAgentPolicy);i.length&&!this.modelBroker&&(e.images=i),await this.rpc.request("steer",e)}get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;modelBroker=null;persistNativeSession=!0;validationRoot=null;runPhase=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,s,e,i){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.agentSessionId=e??null;const a=f("runtime","pi-coding-agent",g(t));this.persistNativeSession=i?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:u.join(a,`validation-${w()}`),this.sessionDir=this.validationRoot?u.join(this.validationRoot,"sessions"):u.join(a,"sessions"),h.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&h.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,s,e,i,a,l){await this.ensureProcess(a);const c=this.requireRpc(),p=await this.readState(),o=!!(p.isStreaming||p.isCompacting);(!o||!this.runId)&&(this.runId=w(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const d=K(s);if(d.modelId&&!o&&(p.model?.id!==d.modelId||d.provider&&p.model?.provider!==d.provider)){if(!d.provider)throw new Error("Pi model selection must include provider/modelId");await c.request("set_model",{provider:d.provider,modelId:d.modelId})}e&&!o&&await c.request("set_thinking_level",{level:e});const r=o?l?.source==="room_activation"?"follow_up":"steer":"prompt",m={message:_(t,i,this.workDir,this.externalChannel,this.shennianSessionId,null)},S=E(i,!this.managedAgentPolicy);S.length&&!this.modelBroker&&(m.images=S),this.modelBroker?.setTurnActive(!0);try{await c.request(r,m)}catch(v){throw this.modelBroker?.setTurnActive(!1),v}}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&this.emitTerminal({state:"aborted"}),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),s=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:s,runId:s?this.runId:null,runPhase:s?this.runPhase??"thinking":null,canStop:s}}async setTitle(t,s){this.rpc&&await this.rpc.request("set_session_name",{name:s.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc)return;const s=x("pi-coding-agent");if(!s)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const e=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];this.agentSessionId&&e.push("--session",this.agentSessionId);const i=await this.prepareHostedModel();if(i&&e.push("--provider","shennian-dashscope","--model","deepseek-v4-flash-0731"),this.managedAgentPolicy&&!P(this.managedAgentPolicy)){e.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const r=this.managedTools(),m=F({outputPath:u.join(f("runtime","pi-coding-agent",g(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});e.push("--no-builtin-tools","--extension",m),r.length?e.push("--tools",r.join(",")):e.push("--no-tools")}const a=D(this.workDir,this.externalChannel,this.shennianSessionId,t),l=this.validationRoot??f("runtime","pi-coding-agent",g(this.shennianSessionId));h.mkdirSync(l,{recursive:!0,mode:448}),this.promptFile=u.join(l,"instructions.md"),h.writeFileSync(this.promptFile,a,{encoding:"utf8",mode:384}),process.platform!=="win32"&&h.chmodSync(this.promptFile,384),e.push("--append-system-prompt",this.promptFile);const c={NO_COLOR:"1",...i?{PI_CODING_AGENT_DIR:i.configDir}:{}},p=this.managedAgentPolicy&&!P(this.managedAgentPolicy)?N({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:c}):this.managedAgentPolicy?b({...c,...this.extraEnv}):T({...c,...this.extraEnv});let o;try{o=R(s,e,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:p})}catch(r){throw await this.stopModelBroker(),r}this.process=o,this.stderr="",o.stderr?.on("data",r=>{const m=typeof r=="string"?r:r.toString("utf8");this.stderr=y(`${this.stderr}${m}`,$)});const d=new B(o);this.rpc=d,d.on("event",r=>this.handleRpcEvent(r)),d.on("protocolError",r=>this.emitError(r.message)),o.once("close",r=>{this.process===o&&(this.process=null,this.rpc=null,this.terminal||this.emitError(r===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${r??"unknown"}${this.stderr?`: ${this.stderr}`:""}`),this.stopModelBroker())}),o.once("error",r=>{this.process===o&&this.emitError(r.message)});try{const r=await this.readState();if(!r.sessionId)throw new Error("Pi RPC did not return a session ID");if(r.isStreaming||r.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&r.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!r.sessionFile||!this.ownsSessionFile(r.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=r.sessionId,this.persistNativeSession&&U(r.sessionId,this.sessionDir)}catch(r){throw await this.stopProcess(),r}}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const s=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&s.push("edit","write");const e=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,i=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(e||i||t.fileAccess==="host-full")&&s.push("bash"),s}ownsSessionFile(t){const s=u.resolve(this.sessionDir),e=u.resolve(t),i=u.relative(s,e);return i!==""&&!i.startsWith("..")&&!u.isAbsolute(i)}async readState(){const t=await this.requireRpc().request("get_state");return H(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=I(t.usage)??this.lastUsage;const s=t.assistantMessageEvent;if(!s||typeof s!="object")return;const e=s;e.type==="text_delta"&&typeof e.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:e.delta})):e.type==="thinking_delta"&&typeof e.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:e.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:X(t.result)||Z(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const s=t.message;if(s&&typeof s=="object"){const e=s;this.lastUsage=I(e.usage)??this.lastUsage,e.stopReason==="error"&&(this.modelBroker?.setTurnActive(!1),this.emitError(typeof e.errorMessage=="string"?e.errorMessage:"Pi model request failed"))}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.modelBroker?.setTurnActive(!1),this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}emitError(t){this.modelBroker?.setTurnActive(!1),this.emitTerminal({state:"error",message:L(t)})}async prepareHostedModel(){const t=M(),s=t.machineToken?.trim();if(!s)return null;const e=new q({serverUrl:t.serverUrl?.trim()||"https://shennian.net",machineToken:s,sessionId:this.shennianSessionId}),i=await e.start(),a=this.validationRoot?u.join(this.validationRoot,"agent-config"):f("runtime","pi-coding-agent",g(this.shennianSessionId),"agent-config");h.mkdirSync(a,{recursive:!0,mode:448}),process.platform!=="win32"&&h.chmodSync(a,448);const l=u.join(a,"models.json"),c={providers:{"shennian-dashscope":{baseUrl:i.baseUrl,api:"openai-completions",apiKey:i.apiKey,authHeader:!0,compat:{supportsDeveloperRole:!1,supportsReasoningEffort:!0},models:[{id:"deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",reasoning:!0,input:["text"],thinkingLevelMap:{off:null,minimal:null,low:"low",medium:null,high:"high",xhigh:null,max:"max"}}]}}};return h.writeFileSync(l,`${JSON.stringify(c,null,2)}
|
|
4
|
+
`,{encoding:"utf8",mode:384}),process.platform!=="win32"&&h.chmodSync(l,384),this.modelBroker=e,{configDir:a}}async stopModelBroker(){const t=this.modelBroker;this.modelBroker=null,await t?.stop().catch(()=>{})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t?(t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const i=()=>{e||(e=!0,s())};t.once("close",i),setTimeout(()=>{t.kill("SIGKILL"),i()},z).unref()}),await this.stopModelBroker()):await this.stopModelBroker(),this.validationRoot&&(h.rmSync(this.validationRoot,{recursive:!0,force:!0}),this.validationRoot=null)}}k("pi-coding-agent",()=>new W);export{W as PiCodingAgentAdapter};
|