@farazirfan/costar-server-executor 1.7.37 → 1.7.39
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/agent/agent.d.ts +90 -0
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +606 -0
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/pi-embedded-runner/run.d.ts.map +1 -1
- package/dist/agent/pi-embedded-runner/run.js +2 -1
- package/dist/agent/pi-embedded-runner/run.js.map +1 -1
- package/dist/agent/pi-embedded-runner/system-prompt.d.ts.map +1 -1
- package/dist/agent/pi-embedded-runner/system-prompt.js +16 -37
- package/dist/agent/pi-embedded-runner/system-prompt.js.map +1 -1
- package/dist/agent/pi-embedded-runner/tools.d.ts +4 -1
- package/dist/agent/pi-embedded-runner/tools.d.ts.map +1 -1
- package/dist/agent/pi-embedded-runner/tools.js +3 -1
- package/dist/agent/pi-embedded-runner/tools.js.map +1 -1
- package/dist/agent/pi-embedded-runner/types.d.ts +4 -0
- package/dist/agent/pi-embedded-runner/types.d.ts.map +1 -1
- package/dist/cli/env-loader.d.ts.map +1 -1
- package/dist/cli/env-loader.js +1 -0
- package/dist/cli/env-loader.js.map +1 -1
- package/dist/cli/setup.js +2 -2
- package/dist/cli/setup.js.map +1 -1
- package/dist/cron/normalize.d.ts +31 -0
- package/dist/cron/normalize.d.ts.map +1 -0
- package/dist/cron/normalize.js +211 -0
- package/dist/cron/normalize.js.map +1 -0
- package/dist/cron/scheduler.d.ts +33 -3
- package/dist/cron/scheduler.d.ts.map +1 -1
- package/dist/cron/scheduler.js +253 -48
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/heartbeat/runner.d.ts +27 -12
- package/dist/heartbeat/runner.d.ts.map +1 -1
- package/dist/heartbeat/runner.js +82 -104
- package/dist/heartbeat/runner.js.map +1 -1
- package/dist/infra/heartbeat-events-filter.d.ts +29 -0
- package/dist/infra/heartbeat-events-filter.d.ts.map +1 -0
- package/dist/infra/heartbeat-events-filter.js +80 -0
- package/dist/infra/heartbeat-events-filter.js.map +1 -0
- package/dist/infra/index.d.ts +9 -0
- package/dist/infra/index.d.ts.map +1 -0
- package/dist/infra/index.js +9 -0
- package/dist/infra/index.js.map +1 -0
- package/dist/infra/system-events.d.ts +58 -2
- package/dist/infra/system-events.d.ts.map +1 -1
- package/dist/infra/system-events.js +80 -14
- package/dist/infra/system-events.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +6 -1
- package/dist/server.js.map +1 -1
- package/dist/services/platform-keys.d.ts +19 -0
- package/dist/services/platform-keys.d.ts.map +1 -0
- package/dist/services/platform-keys.js +74 -0
- package/dist/services/platform-keys.js.map +1 -0
- package/dist/subagent/registry.d.ts +96 -0
- package/dist/subagent/registry.d.ts.map +1 -0
- package/dist/subagent/registry.js +180 -0
- package/dist/subagent/registry.js.map +1 -0
- package/dist/tools/complete-turn.d.ts +2 -2
- package/dist/tools/complete-turn.js +10 -10
- package/dist/tools/complete-turn.js.map +1 -1
- package/dist/tools/contacts.d.ts +13 -0
- package/dist/tools/contacts.d.ts.map +1 -0
- package/dist/tools/contacts.js +80 -0
- package/dist/tools/contacts.js.map +1 -0
- package/dist/tools/cron.d.ts +17 -2
- package/dist/tools/cron.d.ts.map +1 -1
- package/dist/tools/cron.js +117 -35
- package/dist/tools/cron.js.map +1 -1
- package/dist/tools/google-maps.d.ts +6 -6
- package/dist/tools/google-maps.d.ts.map +1 -1
- package/dist/tools/google-maps.js +207 -262
- package/dist/tools/google-maps.js.map +1 -1
- package/dist/tools/index.d.ts +17 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +40 -9
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/phone-call.d.ts +11 -0
- package/dist/tools/phone-call.d.ts.map +1 -0
- package/dist/tools/phone-call.js +151 -0
- package/dist/tools/phone-call.js.map +1 -0
- package/dist/tools/sessions-spawn.d.ts +33 -0
- package/dist/tools/sessions-spawn.d.ts.map +1 -0
- package/dist/tools/sessions-spawn.js +164 -0
- package/dist/tools/sessions-spawn.js.map +1 -0
- package/dist/tools/spotify.d.ts +12 -0
- package/dist/tools/spotify.d.ts.map +1 -0
- package/dist/tools/spotify.js +251 -0
- package/dist/tools/spotify.js.map +1 -0
- package/dist/tools/subagents.d.ts +23 -0
- package/dist/tools/subagents.d.ts.map +1 -0
- package/dist/tools/subagents.js +209 -0
- package/dist/tools/subagents.js.map +1 -0
- package/dist/tools/whatsapp.d.ts +13 -0
- package/dist/tools/whatsapp.d.ts.map +1 -0
- package/dist/tools/whatsapp.js +215 -0
- package/dist/tools/whatsapp.js.map +1 -0
- package/dist/tools/youtube.d.ts +12 -0
- package/dist/tools/youtube.d.ts.map +1 -0
- package/dist/tools/youtube.js +218 -0
- package/dist/tools/youtube.js.map +1 -0
- package/dist/utils/asterizk-auth.d.ts +43 -0
- package/dist/utils/asterizk-auth.d.ts.map +1 -0
- package/dist/utils/asterizk-auth.js +125 -0
- package/dist/utils/asterizk-auth.js.map +1 -0
- package/dist/web-server.d.ts.map +1 -1
- package/dist/web-server.js +132 -0
- package/dist/web-server.js.map +1 -1
- package/dist/workspace/index.d.ts +3 -4
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +3 -4
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/templates.d.ts +8 -7
- package/dist/workspace/templates.d.ts.map +1 -1
- package/dist/workspace/templates.js +18 -127
- package/dist/workspace/templates.js.map +1 -1
- package/dist/workspace/workspace.d.ts +2 -4
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/dist/workspace/workspace.js +7 -16
- package/dist/workspace/workspace.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +231 -0
- package/skills/docx/SKILL.md +468 -0
- package/skills/docx/scripts/__init__.py +1 -0
- package/skills/docx/scripts/accept_changes.py +181 -0
- package/skills/docx/scripts/comment.py +347 -0
- package/skills/docx/scripts/helpers/__init__.py +0 -0
- package/skills/docx/scripts/helpers/merge_runs.py +231 -0
- package/skills/docx/scripts/helpers/simplify_redlines.py +240 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/docx/scripts/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/docx/scripts/ooxml/scripts/pack.py +159 -0
- package/skills/docx/scripts/ooxml/scripts/unpack.py +29 -0
- package/skills/docx/scripts/ooxml/scripts/validate.py +106 -0
- package/skills/docx/scripts/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/docx/scripts/ooxml/scripts/validation/base.py +1023 -0
- package/skills/docx/scripts/ooxml/scripts/validation/docx.py +519 -0
- package/skills/docx/scripts/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/docx/scripts/ooxml/scripts/validation/redlining.py +284 -0
- package/skills/docx/scripts/pack.py +166 -0
- package/skills/docx/scripts/templates/comments.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/skills/docx/scripts/templates/people.xml +3 -0
- package/skills/docx/scripts/unpack.py +134 -0
- package/skills/longform-video-generation/SKILL.md +298 -0
- package/skills/longform-video-generation/references/advanced_techniques.md +474 -0
- package/skills/longform-video-generation/references/google_api_guide.md +288 -0
- package/skills/longform-video-generation/scripts/video_generator.py +579 -0
- package/skills/pdf/FORMS.md +305 -0
- package/skills/pdf/REFERENCE.md +612 -0
- package/skills/pdf/SKILL.md +293 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/skills/pdf/scripts/create_validation_image.py +41 -0
- package/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/skills/pdf/scripts/extract_form_structure.py +124 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +116 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +136 -0
- package/skills/pptx/SKILL.md +171 -0
- package/skills/pptx/editing.md +205 -0
- package/skills/pptx/pptxgenjs.md +377 -0
- package/skills/pptx/scripts/add_slide.py +225 -0
- package/skills/pptx/scripts/clean.py +309 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/pptx/scripts/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/pptx/scripts/ooxml/scripts/pack.py +159 -0
- package/skills/pptx/scripts/ooxml/scripts/unpack.py +29 -0
- package/skills/pptx/scripts/ooxml/scripts/validate.py +106 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/base.py +1023 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/docx.py +519 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/redlining.py +284 -0
- package/skills/pptx/scripts/pack.py +168 -0
- package/skills/pptx/scripts/thumbnail.py +318 -0
- package/skills/pptx/scripts/unpack.py +86 -0
- package/skills/xlsx/SKILL.md +291 -0
- package/skills/xlsx/recalc.py +247 -0
package/dist/agent/agent.js
CHANGED
|
@@ -6,6 +6,7 @@ import { runEmbeddedPiAgent } from "./pi-embedded-runner/run.js";
|
|
|
6
6
|
import { runWithModelFallback } from "./model-fallback.js";
|
|
7
7
|
import { ensureAgentWorkspace, } from "../workspace/index.js";
|
|
8
8
|
import { compactEmbeddedPiSessionDirect } from "./pi-embedded-runner/compact.js";
|
|
9
|
+
import { SessionManager } from "@mariozechner/pi-coding-agent";
|
|
9
10
|
import path from "node:path";
|
|
10
11
|
import os from "node:os";
|
|
11
12
|
import fs from "node:fs";
|
|
@@ -274,6 +275,13 @@ export class Agent {
|
|
|
274
275
|
// Run embedded pi agent (core OpenClaw function)
|
|
275
276
|
// cronDeps is passed through so tools are created inside the runner
|
|
276
277
|
// with full context (OpenClaw pattern: no pre-built tool arrays)
|
|
278
|
+
// subagentDeps provides sessions_spawn + subagents tools to main session
|
|
279
|
+
const subagentDeps = {
|
|
280
|
+
userId: this.userId,
|
|
281
|
+
agent: this,
|
|
282
|
+
maxSpawnDepth: 1,
|
|
283
|
+
maxChildren: 5,
|
|
284
|
+
};
|
|
277
285
|
return await runEmbeddedPiAgent({
|
|
278
286
|
sessionId,
|
|
279
287
|
sessionFile,
|
|
@@ -290,6 +298,7 @@ export class Agent {
|
|
|
290
298
|
runId: sessionId,
|
|
291
299
|
skillEntries,
|
|
292
300
|
cronDeps: this.cronDeps,
|
|
301
|
+
subagentDeps,
|
|
293
302
|
onPartialReply: options.onPartialReply,
|
|
294
303
|
onToolResult: options.onPartialReply,
|
|
295
304
|
onToolStart: options.onToolStart,
|
|
@@ -564,6 +573,153 @@ export class Agent {
|
|
|
564
573
|
this._busy = false;
|
|
565
574
|
}
|
|
566
575
|
}
|
|
576
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
577
|
+
// SUB-AGENT SESSION SUPPORT
|
|
578
|
+
// Pattern: OpenClaw's subagent-spawn.ts — runs child worker in isolated
|
|
579
|
+
// session. Unlike runIsolatedAgentTurn, this does NOT set _busy, uses
|
|
580
|
+
// unique session per spawn, and strips spawn/cron/message tools.
|
|
581
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
582
|
+
/**
|
|
583
|
+
* Run a sub-agent in an isolated session (fire-and-forget pattern).
|
|
584
|
+
* Similar to runIsolatedAgentTurn but designed for concurrent spawning:
|
|
585
|
+
*
|
|
586
|
+
* Key differences from runIsolatedAgentTurn:
|
|
587
|
+
* 1. Does NOT set this._busy — multiple sub-agents can run concurrently
|
|
588
|
+
* 2. Unique session per spawn — no session reuse/freshness logic
|
|
589
|
+
* 3. No cronDeps — sub-agents can't create cron jobs
|
|
590
|
+
* 4. No subagentDeps — sub-agents can't spawn (depth limit enforcement)
|
|
591
|
+
* 5. Passes abortSignal for kill support
|
|
592
|
+
* 6. deleteAfterRun defaults to true (one-shot tasks)
|
|
593
|
+
*
|
|
594
|
+
* Pattern: OpenClaw's spawnSubagentDirect + runCronIsolatedAgentTurn
|
|
595
|
+
*/
|
|
596
|
+
async runSubagentTurn(prompt, options = {}) {
|
|
597
|
+
// NOTE: Does NOT set this._busy — sub-agents run concurrently
|
|
598
|
+
// Unique session per sub-agent (no reuse, no store file)
|
|
599
|
+
const subagentSessionId = `${this.userId}-subagent-${crypto.randomUUID()}`;
|
|
600
|
+
const subagentSessionFile = path.join(this.sessionDir, `${subagentSessionId}.json`);
|
|
601
|
+
const deleteAfterRun = options.deleteAfterRun !== false; // Default: true
|
|
602
|
+
const timeoutMs = options.timeoutMs ?? 600_000;
|
|
603
|
+
try {
|
|
604
|
+
console.log(`\n${"─".repeat(60)}`);
|
|
605
|
+
console.log(`[AGENT] Starting SUB-AGENT turn`);
|
|
606
|
+
console.log(`[AGENT] Sub-agent session: ${subagentSessionId}`);
|
|
607
|
+
console.log(`[AGENT] Sub-agent file: ${subagentSessionFile}`);
|
|
608
|
+
console.log(`[AGENT] Provider/Model: ${this.getProviderModel()}`);
|
|
609
|
+
if (options.sessionLabel) {
|
|
610
|
+
console.log(`[AGENT] Label: ${options.sessionLabel}`);
|
|
611
|
+
}
|
|
612
|
+
// Ensure workspace files exist (same as regular turn)
|
|
613
|
+
if (!this.workspaceSynced) {
|
|
614
|
+
await this.syncWorkspaceFromStorage();
|
|
615
|
+
}
|
|
616
|
+
const [provider, model] = this.parseProviderModel();
|
|
617
|
+
const skillEntries = this.buildSkillEntries();
|
|
618
|
+
// Build special system prompt for sub-agent sessions
|
|
619
|
+
const subagentSystemPrompt = buildIsolatedSessionSystemPrompt({
|
|
620
|
+
label: options.sessionLabel,
|
|
621
|
+
});
|
|
622
|
+
// Run with model fallback using the SUB-AGENT session file
|
|
623
|
+
const fallbackResult = await runWithModelFallback({
|
|
624
|
+
cfg: this.config,
|
|
625
|
+
provider,
|
|
626
|
+
model,
|
|
627
|
+
agentDir: process.cwd(),
|
|
628
|
+
run: async (fallbackProvider, fallbackModel) => {
|
|
629
|
+
console.log(`[AGENT] Sub-agent run with ${fallbackProvider}/${fallbackModel}`);
|
|
630
|
+
return await runEmbeddedPiAgent({
|
|
631
|
+
sessionId: subagentSessionId,
|
|
632
|
+
sessionFile: subagentSessionFile,
|
|
633
|
+
workspaceDir: this.workspaceDir,
|
|
634
|
+
agentDir: process.cwd(),
|
|
635
|
+
config: this.config,
|
|
636
|
+
prompt,
|
|
637
|
+
provider: fallbackProvider,
|
|
638
|
+
model: fallbackModel,
|
|
639
|
+
thinkLevel: "off",
|
|
640
|
+
verboseLevel: "normal",
|
|
641
|
+
reasoningLevel: "off",
|
|
642
|
+
timeoutMs,
|
|
643
|
+
runId: subagentSessionId,
|
|
644
|
+
skillEntries,
|
|
645
|
+
// NOTE: No cronDeps — sub-agents can't create cron jobs
|
|
646
|
+
// NOTE: No subagentDeps — sub-agents can't spawn (tool stripping)
|
|
647
|
+
// Lane isolation
|
|
648
|
+
lane: "subagent",
|
|
649
|
+
// Disable message tool — output goes through announce pipeline
|
|
650
|
+
disableMessageTool: true,
|
|
651
|
+
// Special system prompt for sub-agent sessions
|
|
652
|
+
extraSystemPrompt: subagentSystemPrompt,
|
|
653
|
+
// Abort signal for kill support
|
|
654
|
+
abortSignal: options.abortSignal,
|
|
655
|
+
});
|
|
656
|
+
},
|
|
657
|
+
});
|
|
658
|
+
const result = fallbackResult.result;
|
|
659
|
+
console.log(`[AGENT] Sub-agent run completed with ${fallbackResult.provider}/${fallbackResult.model}`);
|
|
660
|
+
console.log(`[AGENT] Duration: ${result.meta.durationMs}ms`);
|
|
661
|
+
console.log(`[AGENT] Tokens: ${result.meta.agentMeta.usage?.inputTokens}/${result.meta.agentMeta.usage?.outputTokens}`);
|
|
662
|
+
if (result.didSendViaMessagingTool) {
|
|
663
|
+
console.log(`[AGENT] Sub-agent sent via messaging tool — will skip announce to avoid duplicate`);
|
|
664
|
+
}
|
|
665
|
+
// Extract response text
|
|
666
|
+
const payloads = result.payloads ?? [];
|
|
667
|
+
const outputText = pickLastNonEmptyText(payloads) ?? "";
|
|
668
|
+
return {
|
|
669
|
+
success: !result.meta.error,
|
|
670
|
+
response: outputText,
|
|
671
|
+
outputText,
|
|
672
|
+
toolCalls: 0,
|
|
673
|
+
stopReason: result.meta.stopReason,
|
|
674
|
+
turns: 1,
|
|
675
|
+
inputTokens: result.meta.agentMeta.usage?.inputTokens ?? 0,
|
|
676
|
+
outputTokens: result.meta.agentMeta.usage?.outputTokens ?? 0,
|
|
677
|
+
error: result.meta.error?.message,
|
|
678
|
+
didSendViaMessagingTool: result.didSendViaMessagingTool ?? false,
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
catch (error) {
|
|
682
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
683
|
+
console.error(`[AGENT] Sub-agent turn error:`, message);
|
|
684
|
+
return {
|
|
685
|
+
success: false,
|
|
686
|
+
error: message,
|
|
687
|
+
turns: 1,
|
|
688
|
+
didSendViaMessagingTool: false,
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
finally {
|
|
692
|
+
// Session cleanup — default: DELETE (sub-agent sessions are one-shot)
|
|
693
|
+
if (deleteAfterRun) {
|
|
694
|
+
try {
|
|
695
|
+
if (fs.existsSync(subagentSessionFile)) {
|
|
696
|
+
fs.unlinkSync(subagentSessionFile);
|
|
697
|
+
console.log(`[AGENT] Cleaned up sub-agent session: ${subagentSessionFile}`);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
catch (err) {
|
|
701
|
+
console.warn(`[AGENT] Failed to clean up sub-agent session:`, err);
|
|
702
|
+
}
|
|
703
|
+
// Clean up backup files
|
|
704
|
+
try {
|
|
705
|
+
const dir = path.dirname(subagentSessionFile);
|
|
706
|
+
const base = path.basename(subagentSessionFile);
|
|
707
|
+
const files = fs.readdirSync(dir);
|
|
708
|
+
for (const f of files) {
|
|
709
|
+
if (f.startsWith(base) && f.endsWith(".bak")) {
|
|
710
|
+
fs.unlinkSync(path.join(dir, f));
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
// best-effort
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
console.log(`[AGENT] Kept sub-agent session file: ${subagentSessionFile}`);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
567
723
|
/**
|
|
568
724
|
* Inject an isolated run's result into the MAIN session as a compact
|
|
569
725
|
* system message. The main agent sees one summary message and decides
|
|
@@ -608,6 +764,456 @@ export class Agent {
|
|
|
608
764
|
// Execute in the MAIN session — agent sees one compact message
|
|
609
765
|
return await this.executeTurn(triggerMessage, { maxTurns: 25 });
|
|
610
766
|
}
|
|
767
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
768
|
+
// CLIENT SESSION API
|
|
769
|
+
// Shared main session between client (Flutter) and server (TypeScript).
|
|
770
|
+
// Client reads/writes generic {role, content} messages; server translates
|
|
771
|
+
// to/from pi-agent JSONL session format. Follows OpenClaw isolated session pattern.
|
|
772
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
773
|
+
_clientTurnActive = false;
|
|
774
|
+
_clientLockTimeout = null;
|
|
775
|
+
/**
|
|
776
|
+
* Acquire the main session for a client turn.
|
|
777
|
+
* Sets _busy = true to prevent server merges (injectIsolatedResult)
|
|
778
|
+
* while client is running its agent loop.
|
|
779
|
+
* Auto-expires after 5 min as safety against client crashes.
|
|
780
|
+
*/
|
|
781
|
+
acquireForClient() {
|
|
782
|
+
if (this._busy)
|
|
783
|
+
return false;
|
|
784
|
+
this._busy = true;
|
|
785
|
+
this._clientTurnActive = true;
|
|
786
|
+
// Auto-expire after 5 min (safety: client crash/disconnect)
|
|
787
|
+
this._clientLockTimeout = setTimeout(() => {
|
|
788
|
+
if (this._clientTurnActive) {
|
|
789
|
+
console.warn("[AGENT] Client lock auto-expired after 5 min");
|
|
790
|
+
this._busy = false;
|
|
791
|
+
this._clientTurnActive = false;
|
|
792
|
+
}
|
|
793
|
+
}, 300_000);
|
|
794
|
+
console.log("[AGENT] Client acquired main session");
|
|
795
|
+
return true;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Release the main session after client turn completes.
|
|
799
|
+
*/
|
|
800
|
+
releaseClient() {
|
|
801
|
+
this._clientTurnActive = false;
|
|
802
|
+
this._busy = false;
|
|
803
|
+
if (this._clientLockTimeout) {
|
|
804
|
+
clearTimeout(this._clientLockTimeout);
|
|
805
|
+
this._clientLockTimeout = null;
|
|
806
|
+
}
|
|
807
|
+
console.log("[AGENT] Client released main session");
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Check if client currently holds the session.
|
|
811
|
+
*/
|
|
812
|
+
isClientTurnActive() {
|
|
813
|
+
return this._clientTurnActive;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Read the main session as generic {role, content} messages.
|
|
817
|
+
* Converts pi-agent JSONL → generic message format.
|
|
818
|
+
* Server tool calls are summarized as text (client doesn't have server tool schemas).
|
|
819
|
+
*/
|
|
820
|
+
getSessionMessages(tokenLimit = 15000) {
|
|
821
|
+
if (!fs.existsSync(this.sessionFile)) {
|
|
822
|
+
return { messages: [], tokenCount: 0 };
|
|
823
|
+
}
|
|
824
|
+
try {
|
|
825
|
+
// Open session and build context (resolves compaction, tree traversal)
|
|
826
|
+
const manager = SessionManager.open(this.sessionFile);
|
|
827
|
+
const context = manager.buildSessionContext();
|
|
828
|
+
// Convert pi-agent AgentMessages → generic messages
|
|
829
|
+
const genericMessages = this.convertToGenericMessages(context.messages);
|
|
830
|
+
// Trim to tokenLimit from the end (keep most recent)
|
|
831
|
+
const trimmed = this.trimToTokenLimit(genericMessages, tokenLimit);
|
|
832
|
+
// Estimate total token count
|
|
833
|
+
const tokenCount = this.estimateMessageTokens(trimmed);
|
|
834
|
+
return { messages: trimmed, tokenCount };
|
|
835
|
+
}
|
|
836
|
+
catch (err) {
|
|
837
|
+
console.error("[AGENT] Error reading session messages:", err);
|
|
838
|
+
return { messages: [], tokenCount: 0 };
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Append generic {role, content} messages to the main session as JSONL entries.
|
|
843
|
+
* Converts generic message format → pi-agent JSONL.
|
|
844
|
+
* Optionally triggers compaction if session grows too large.
|
|
845
|
+
*/
|
|
846
|
+
async appendClientMessages(messages) {
|
|
847
|
+
try {
|
|
848
|
+
// Open or create session
|
|
849
|
+
let manager;
|
|
850
|
+
if (fs.existsSync(this.sessionFile)) {
|
|
851
|
+
manager = SessionManager.open(this.sessionFile);
|
|
852
|
+
}
|
|
853
|
+
else {
|
|
854
|
+
manager = SessionManager.create(this.workspaceDir, this.sessionDir);
|
|
855
|
+
// Rename to our expected session file if different
|
|
856
|
+
const createdFile = manager.getSessionFile() || "";
|
|
857
|
+
if (createdFile && createdFile !== this.sessionFile) {
|
|
858
|
+
// Move it to expected location
|
|
859
|
+
fs.renameSync(createdFile, this.sessionFile);
|
|
860
|
+
manager = SessionManager.open(this.sessionFile);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
// Convert generic messages → pi-agent messages and append
|
|
864
|
+
for (const msg of messages) {
|
|
865
|
+
const piMessage = this.convertFromGenericMessage(msg);
|
|
866
|
+
if (piMessage) {
|
|
867
|
+
manager.appendMessage(piMessage);
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
// Check if compaction is needed (estimate tokens)
|
|
871
|
+
const context = manager.buildSessionContext();
|
|
872
|
+
let totalTokens = 0;
|
|
873
|
+
for (const m of context.messages) {
|
|
874
|
+
totalTokens += this.estimatePiMessageTokens(m);
|
|
875
|
+
}
|
|
876
|
+
let compacted = false;
|
|
877
|
+
// Trigger compaction if over 150k tokens (leave room for response)
|
|
878
|
+
if (totalTokens > 150_000) {
|
|
879
|
+
console.log(`[AGENT] Session at ${totalTokens} tokens after client append — triggering compaction`);
|
|
880
|
+
try {
|
|
881
|
+
const result = await this.compactSession();
|
|
882
|
+
compacted = result.compacted === true;
|
|
883
|
+
}
|
|
884
|
+
catch (err) {
|
|
885
|
+
console.error("[AGENT] Post-append compaction failed:", err);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
return { compacted };
|
|
889
|
+
}
|
|
890
|
+
catch (err) {
|
|
891
|
+
console.error("[AGENT] Error appending client messages:", err);
|
|
892
|
+
return { compacted: false };
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Mid-turn compaction for client overflow recovery.
|
|
897
|
+
* Takes in-memory generic messages, runs pi-agent compaction,
|
|
898
|
+
* returns compacted generic messages sized to fit targetContextTokens.
|
|
899
|
+
* Does NOT write to session file (client is still mid-turn).
|
|
900
|
+
* Uses server's configured model for summarization (model-agnostic).
|
|
901
|
+
*/
|
|
902
|
+
async compactClientContext(messages, targetContextTokens) {
|
|
903
|
+
try {
|
|
904
|
+
// Convert generic messages → pi-agent messages
|
|
905
|
+
const piMessages = [];
|
|
906
|
+
for (const msg of messages) {
|
|
907
|
+
const piMsg = this.convertFromGenericMessage(msg);
|
|
908
|
+
if (piMsg)
|
|
909
|
+
piMessages.push(piMsg);
|
|
910
|
+
}
|
|
911
|
+
// Create a temporary in-memory session with these messages
|
|
912
|
+
const tempSessionFile = path.join(this.sessionDir, `${this.userId}-compact-temp-${crypto.randomUUID()}.json`);
|
|
913
|
+
try {
|
|
914
|
+
// Create temp session and populate it
|
|
915
|
+
const tempManager = SessionManager.create(this.workspaceDir, this.sessionDir);
|
|
916
|
+
const tempCreatedFile = tempManager.getSessionFile() || "";
|
|
917
|
+
// Append all messages to temp session
|
|
918
|
+
for (const piMsg of piMessages) {
|
|
919
|
+
tempManager.appendMessage(piMsg);
|
|
920
|
+
}
|
|
921
|
+
// Rename to expected path
|
|
922
|
+
if (tempCreatedFile && tempCreatedFile !== tempSessionFile) {
|
|
923
|
+
fs.renameSync(tempCreatedFile, tempSessionFile);
|
|
924
|
+
}
|
|
925
|
+
// Run pi-agent compaction on the temp session
|
|
926
|
+
const [provider, model] = this.parseProviderModel();
|
|
927
|
+
const compactParams = {
|
|
928
|
+
sessionId: `compact-temp-${Date.now()}`,
|
|
929
|
+
sessionFile: tempSessionFile,
|
|
930
|
+
workspaceDir: this.workspaceDir,
|
|
931
|
+
agentDir: process.cwd(),
|
|
932
|
+
config: this.config,
|
|
933
|
+
provider,
|
|
934
|
+
model,
|
|
935
|
+
thinkLevel: "off",
|
|
936
|
+
customInstructions: `Summarize preserving all important context. Target: fit within ${targetContextTokens} tokens.`,
|
|
937
|
+
};
|
|
938
|
+
await compactEmbeddedPiSessionDirect(compactParams);
|
|
939
|
+
// Read back the compacted session
|
|
940
|
+
const compactedManager = SessionManager.open(tempSessionFile);
|
|
941
|
+
const compactedContext = compactedManager.buildSessionContext();
|
|
942
|
+
// Convert back to generic messages
|
|
943
|
+
const compactedMessages = this.convertToGenericMessages(compactedContext.messages);
|
|
944
|
+
const tokenCount = this.estimateMessageTokens(compactedMessages);
|
|
945
|
+
return { messages: compactedMessages, tokenCount };
|
|
946
|
+
}
|
|
947
|
+
finally {
|
|
948
|
+
// Cleanup temp file
|
|
949
|
+
try {
|
|
950
|
+
if (fs.existsSync(tempSessionFile))
|
|
951
|
+
fs.unlinkSync(tempSessionFile);
|
|
952
|
+
}
|
|
953
|
+
catch {
|
|
954
|
+
// best-effort cleanup
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
catch (err) {
|
|
959
|
+
console.error("[AGENT] Client context compaction failed:", err);
|
|
960
|
+
// Return original messages if compaction fails
|
|
961
|
+
return { messages, tokenCount: this.estimateMessageTokens(messages) };
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
// ── Generic message ↔ Pi-agent message conversion helpers ──
|
|
965
|
+
/**
|
|
966
|
+
* Convert pi-agent AgentMessages → generic {role, content} messages.
|
|
967
|
+
* Server tool calls are summarized as text to avoid exposing
|
|
968
|
+
* server-only tool schemas to the client.
|
|
969
|
+
*/
|
|
970
|
+
convertToGenericMessages(piMessages) {
|
|
971
|
+
const result = [];
|
|
972
|
+
// Known client tool names — tools that exist on the Flutter client.
|
|
973
|
+
// Server-only tools (browser, exec, pty, etc.) get summarized as text.
|
|
974
|
+
// We detect server tools by checking if the message has assistant metadata
|
|
975
|
+
// from the server's pi-agent runs (provider/model fields).
|
|
976
|
+
for (let i = 0; i < piMessages.length; i++) {
|
|
977
|
+
const msg = piMessages[i];
|
|
978
|
+
if (msg.role === "user") {
|
|
979
|
+
// User messages pass through directly
|
|
980
|
+
if (typeof msg.content === "string") {
|
|
981
|
+
result.push({ role: "user", content: msg.content });
|
|
982
|
+
}
|
|
983
|
+
else if (Array.isArray(msg.content)) {
|
|
984
|
+
// Content blocks array
|
|
985
|
+
const blocks = msg.content.map((block) => {
|
|
986
|
+
if (block.type === "text")
|
|
987
|
+
return { type: "text", text: block.text };
|
|
988
|
+
if (block.type === "image")
|
|
989
|
+
return { type: "image", source: { type: "base64", media_type: block.mimeType, data: block.data } };
|
|
990
|
+
return block;
|
|
991
|
+
});
|
|
992
|
+
result.push({ role: "user", content: blocks });
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
else if (msg.role === "assistant") {
|
|
996
|
+
// Assistant messages: convert content blocks
|
|
997
|
+
if (!Array.isArray(msg.content))
|
|
998
|
+
continue;
|
|
999
|
+
const blocks = [];
|
|
1000
|
+
for (const block of msg.content) {
|
|
1001
|
+
if (block.type === "text" && block.text) {
|
|
1002
|
+
blocks.push({ type: "text", text: block.text });
|
|
1003
|
+
}
|
|
1004
|
+
else if (block.type === "toolCall") {
|
|
1005
|
+
blocks.push({
|
|
1006
|
+
type: "tool_use",
|
|
1007
|
+
id: block.id,
|
|
1008
|
+
name: block.name,
|
|
1009
|
+
input: block.arguments || {},
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
else if (block.type === "thinking" && block.thinking) {
|
|
1013
|
+
// Include thinking blocks for models that support it
|
|
1014
|
+
blocks.push({ type: "thinking", thinking: block.thinking });
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
if (blocks.length > 0) {
|
|
1018
|
+
result.push({ role: "assistant", content: blocks });
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
else if (msg.role === "toolResult") {
|
|
1022
|
+
// Tool results → Claude API tool_result blocks within user message
|
|
1023
|
+
const textContent = Array.isArray(msg.content)
|
|
1024
|
+
? msg.content.map((c) => c.type === "text" ? c.text : "").join("")
|
|
1025
|
+
: String(msg.content || "");
|
|
1026
|
+
result.push({
|
|
1027
|
+
role: "user",
|
|
1028
|
+
content: [
|
|
1029
|
+
{
|
|
1030
|
+
type: "tool_result",
|
|
1031
|
+
tool_use_id: msg.toolCallId,
|
|
1032
|
+
content: textContent,
|
|
1033
|
+
is_error: msg.isError || false,
|
|
1034
|
+
},
|
|
1035
|
+
],
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
else if (msg.role === "compactionSummary") {
|
|
1039
|
+
// Compaction summaries → user message with context prefix
|
|
1040
|
+
result.push({
|
|
1041
|
+
role: "user",
|
|
1042
|
+
content: `[Previous conversation summary]\n${msg.summary}`,
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
else if (msg.role === "branchSummary") {
|
|
1046
|
+
// Branch summaries → user message
|
|
1047
|
+
result.push({
|
|
1048
|
+
role: "user",
|
|
1049
|
+
content: `[Branch summary]\n${msg.summary}`,
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
else if (msg.role === "custom" && msg.display !== false) {
|
|
1053
|
+
// Custom messages that should be displayed
|
|
1054
|
+
const content = typeof msg.content === "string"
|
|
1055
|
+
? msg.content
|
|
1056
|
+
: Array.isArray(msg.content)
|
|
1057
|
+
? msg.content.map((c) => c.text || "").join("")
|
|
1058
|
+
: "";
|
|
1059
|
+
if (content) {
|
|
1060
|
+
result.push({ role: "user", content });
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
// Skip bashExecution and other non-standard roles
|
|
1064
|
+
}
|
|
1065
|
+
return result;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Convert a single generic {role, content} message → pi-agent message format.
|
|
1069
|
+
* Used when appending client turn messages to the session.
|
|
1070
|
+
*/
|
|
1071
|
+
convertFromGenericMessage(msg) {
|
|
1072
|
+
const role = msg.role;
|
|
1073
|
+
const content = msg.content;
|
|
1074
|
+
const timestamp = Date.now();
|
|
1075
|
+
if (role === "user") {
|
|
1076
|
+
if (typeof content === "string") {
|
|
1077
|
+
return { role: "user", content, timestamp };
|
|
1078
|
+
}
|
|
1079
|
+
// Check if it's a tool_result array
|
|
1080
|
+
if (Array.isArray(content)) {
|
|
1081
|
+
const firstBlock = content[0];
|
|
1082
|
+
if (firstBlock?.type === "tool_result") {
|
|
1083
|
+
// This is actually a tool result message
|
|
1084
|
+
return {
|
|
1085
|
+
role: "toolResult",
|
|
1086
|
+
toolCallId: firstBlock.tool_use_id,
|
|
1087
|
+
toolName: "", // Not available in generic message format
|
|
1088
|
+
content: [{ type: "text", text: firstBlock.content || "" }],
|
|
1089
|
+
isError: firstBlock.is_error || false,
|
|
1090
|
+
timestamp,
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
// Regular user message with content blocks
|
|
1094
|
+
const blocks = content.map((block) => {
|
|
1095
|
+
if (block.type === "text")
|
|
1096
|
+
return { type: "text", text: block.text };
|
|
1097
|
+
if (block.type === "image") {
|
|
1098
|
+
return {
|
|
1099
|
+
type: "image",
|
|
1100
|
+
data: block.source?.data || "",
|
|
1101
|
+
mimeType: block.source?.media_type || "image/png",
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
return block;
|
|
1105
|
+
});
|
|
1106
|
+
return { role: "user", content: blocks, timestamp };
|
|
1107
|
+
}
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1110
|
+
if (role === "assistant") {
|
|
1111
|
+
if (!Array.isArray(content)) {
|
|
1112
|
+
return { role: "assistant", content: [{ type: "text", text: String(content || "") }], timestamp };
|
|
1113
|
+
}
|
|
1114
|
+
// Convert generic content blocks → pi-agent content blocks
|
|
1115
|
+
const blocks = content.map((block) => {
|
|
1116
|
+
if (block.type === "text")
|
|
1117
|
+
return { type: "text", text: block.text };
|
|
1118
|
+
if (block.type === "tool_use") {
|
|
1119
|
+
return {
|
|
1120
|
+
type: "toolCall",
|
|
1121
|
+
id: block.id,
|
|
1122
|
+
name: block.name,
|
|
1123
|
+
arguments: block.input || {},
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1126
|
+
if (block.type === "thinking")
|
|
1127
|
+
return { type: "thinking", thinking: block.thinking };
|
|
1128
|
+
return block;
|
|
1129
|
+
});
|
|
1130
|
+
return {
|
|
1131
|
+
role: "assistant",
|
|
1132
|
+
content: blocks,
|
|
1133
|
+
timestamp,
|
|
1134
|
+
// Minimal metadata — server doesn't need full provider info for client turns
|
|
1135
|
+
stopReason: "stop",
|
|
1136
|
+
};
|
|
1137
|
+
}
|
|
1138
|
+
return null;
|
|
1139
|
+
}
|
|
1140
|
+
/**
|
|
1141
|
+
* Trim generic messages to fit within a token limit.
|
|
1142
|
+
* Keeps the most recent messages.
|
|
1143
|
+
*/
|
|
1144
|
+
trimToTokenLimit(messages, tokenLimit) {
|
|
1145
|
+
if (messages.length === 0)
|
|
1146
|
+
return messages;
|
|
1147
|
+
// Estimate total tokens
|
|
1148
|
+
const total = this.estimateMessageTokens(messages);
|
|
1149
|
+
if (total <= tokenLimit)
|
|
1150
|
+
return messages;
|
|
1151
|
+
// Work backwards, accumulating tokens
|
|
1152
|
+
const result = [];
|
|
1153
|
+
let accumulated = 0;
|
|
1154
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1155
|
+
const msgTokens = this.estimateMessageTokens([messages[i]]);
|
|
1156
|
+
if (accumulated + msgTokens > tokenLimit && result.length > 0)
|
|
1157
|
+
break;
|
|
1158
|
+
result.unshift(messages[i]);
|
|
1159
|
+
accumulated += msgTokens;
|
|
1160
|
+
}
|
|
1161
|
+
return result;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Estimate token count for generic messages.
|
|
1165
|
+
* Uses chars/4 approximation (same as pi-agent).
|
|
1166
|
+
*/
|
|
1167
|
+
estimateMessageTokens(messages) {
|
|
1168
|
+
let totalChars = 0;
|
|
1169
|
+
for (const msg of messages) {
|
|
1170
|
+
const m = msg;
|
|
1171
|
+
const content = m.content;
|
|
1172
|
+
if (typeof content === "string") {
|
|
1173
|
+
totalChars += content.length;
|
|
1174
|
+
}
|
|
1175
|
+
else if (Array.isArray(content)) {
|
|
1176
|
+
for (const block of content) {
|
|
1177
|
+
const b = block;
|
|
1178
|
+
if (b.text)
|
|
1179
|
+
totalChars += String(b.text).length;
|
|
1180
|
+
if (b.thinking)
|
|
1181
|
+
totalChars += String(b.thinking).length;
|
|
1182
|
+
if (b.content)
|
|
1183
|
+
totalChars += String(b.content).length; // tool_result content
|
|
1184
|
+
if (b.input)
|
|
1185
|
+
totalChars += JSON.stringify(b.input).length; // tool_use input
|
|
1186
|
+
if (b.name)
|
|
1187
|
+
totalChars += String(b.name).length;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return Math.ceil(totalChars / 4);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Estimate token count for a pi-agent message.
|
|
1195
|
+
*/
|
|
1196
|
+
estimatePiMessageTokens(msg) {
|
|
1197
|
+
let chars = 0;
|
|
1198
|
+
if (typeof msg.content === "string") {
|
|
1199
|
+
chars = msg.content.length;
|
|
1200
|
+
}
|
|
1201
|
+
else if (Array.isArray(msg.content)) {
|
|
1202
|
+
for (const block of msg.content) {
|
|
1203
|
+
if (block.text)
|
|
1204
|
+
chars += block.text.length;
|
|
1205
|
+
if (block.thinking)
|
|
1206
|
+
chars += block.thinking.length;
|
|
1207
|
+
if (block.arguments)
|
|
1208
|
+
chars += JSON.stringify(block.arguments).length;
|
|
1209
|
+
if (block.name)
|
|
1210
|
+
chars += block.name.length;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
if (msg.summary)
|
|
1214
|
+
chars += msg.summary.length;
|
|
1215
|
+
return Math.ceil(chars / 4);
|
|
1216
|
+
}
|
|
611
1217
|
/**
|
|
612
1218
|
* Get conversation history
|
|
613
1219
|
*/
|