@synap-core/cli 1.7.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-chat.d.ts +47 -0
- package/dist/commands/agent-chat.js +250 -0
- package/dist/commands/agent-chat.js.map +1 -0
- package/dist/commands/agent-run.d.ts +47 -0
- package/dist/commands/agent-run.js +301 -0
- package/dist/commands/agent-run.js.map +1 -0
- package/dist/commands/agents.js +85 -46
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/artifact.d.ts +26 -0
- package/dist/commands/artifact.js +76 -0
- package/dist/commands/artifact.js.map +1 -0
- package/dist/commands/automation.d.ts +47 -0
- package/dist/commands/automation.js +601 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/bridge-setup.d.ts +66 -0
- package/dist/commands/bridge-setup.js +1112 -0
- package/dist/commands/bridge-setup.js.map +1 -0
- package/dist/commands/cap-connections.d.ts +28 -0
- package/dist/commands/cap-connections.js +224 -0
- package/dist/commands/cap-connections.js.map +1 -0
- package/dist/commands/capability.d.ts +89 -0
- package/dist/commands/capability.js +1523 -0
- package/dist/commands/capability.js.map +1 -0
- package/dist/commands/cell.d.ts +55 -0
- package/dist/commands/cell.js +277 -0
- package/dist/commands/cell.js.map +1 -0
- package/dist/commands/centrality.d.ts +20 -0
- package/dist/commands/centrality.js +94 -0
- package/dist/commands/centrality.js.map +1 -0
- package/dist/commands/connect.d.ts +2 -0
- package/dist/commands/connect.js +25 -10
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connections.js +0 -16
- package/dist/commands/connections.js.map +1 -1
- package/dist/commands/context.d.ts +22 -0
- package/dist/commands/context.js +149 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/data-extra.d.ts +14 -0
- package/dist/commands/data-extra.js +185 -0
- package/dist/commands/data-extra.js.map +1 -0
- package/dist/commands/data.d.ts +14 -10
- package/dist/commands/data.js +353 -192
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/diagnose.d.ts +20 -0
- package/dist/commands/diagnose.js +143 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/digest.d.ts +17 -0
- package/dist/commands/digest.js +121 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/discover.d.ts +2 -0
- package/dist/commands/discover.js +25 -8
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/doc.d.ts +39 -0
- package/dist/commands/doc.js +130 -0
- package/dist/commands/doc.js.map +1 -0
- package/dist/commands/events.d.ts +26 -0
- package/dist/commands/events.js +69 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/explain.d.ts +21 -0
- package/dist/commands/explain.js +251 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/facet.d.ts +29 -0
- package/dist/commands/facet.js +113 -0
- package/dist/commands/facet.js.map +1 -0
- package/dist/commands/graph.d.ts +18 -0
- package/dist/commands/graph.js +74 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/home.d.ts +12 -0
- package/dist/commands/home.js +54 -0
- package/dist/commands/home.js.map +1 -0
- package/dist/commands/import.d.ts +38 -0
- package/dist/commands/import.js +440 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.d.ts +0 -2
- package/dist/commands/init.js +97 -118
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +9 -0
- package/dist/commands/keys.js +78 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/knowledge.d.ts +34 -18
- package/dist/commands/knowledge.js +355 -57
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/launch.d.ts +50 -0
- package/dist/commands/launch.js +790 -0
- package/dist/commands/launch.js.map +1 -0
- package/dist/commands/lens.d.ts +45 -0
- package/dist/commands/lens.js +386 -0
- package/dist/commands/lens.js.map +1 -0
- package/dist/commands/market.d.ts +209 -0
- package/dist/commands/market.js +1368 -0
- package/dist/commands/market.js.map +1 -0
- package/dist/commands/mcp.d.ts +42 -0
- package/dist/commands/mcp.js +184 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/observe.d.ts +9 -0
- package/dist/commands/observe.js +93 -0
- package/dist/commands/observe.js.map +1 -0
- package/dist/commands/open.d.ts +32 -0
- package/dist/commands/open.js +85 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/pod.d.ts +100 -0
- package/dist/commands/pod.js +359 -0
- package/dist/commands/pod.js.map +1 -0
- package/dist/commands/pods.d.ts +6 -0
- package/dist/commands/pods.js +160 -50
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.d.ts +7 -0
- package/dist/commands/proposals-actions.js +77 -0
- package/dist/commands/proposals-actions.js.map +1 -0
- package/dist/commands/providers.d.ts +38 -0
- package/dist/commands/providers.js +170 -0
- package/dist/commands/providers.js.map +1 -0
- package/dist/commands/purge.d.ts +23 -0
- package/dist/commands/purge.js +148 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/raycast.d.ts +15 -0
- package/dist/commands/raycast.js +153 -0
- package/dist/commands/raycast.js.map +1 -0
- package/dist/commands/sessions.d.ts +31 -0
- package/dist/commands/sessions.js +248 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/skill-manage.d.ts +21 -0
- package/dist/commands/skill-manage.js +195 -0
- package/dist/commands/skill-manage.js.map +1 -0
- package/dist/commands/skills-commands.d.ts +26 -0
- package/dist/commands/skills-commands.js +187 -0
- package/dist/commands/skills-commands.js.map +1 -0
- package/dist/commands/skills.d.ts +26 -0
- package/dist/commands/skills.js +196 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.d.ts +3 -1
- package/dist/commands/status.js +231 -41
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.d.ts +24 -0
- package/dist/commands/statusline.js +450 -0
- package/dist/commands/statusline.js.map +1 -0
- package/dist/commands/subscribe.d.ts +19 -0
- package/dist/commands/subscribe.js +91 -0
- package/dist/commands/subscribe.js.map +1 -0
- package/dist/commands/tools.d.ts +30 -0
- package/dist/commands/tools.js +315 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/versions.d.ts +27 -0
- package/dist/commands/versions.js +277 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/commands/view.d.ts +57 -0
- package/dist/commands/view.js +195 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/commands/whoami.d.ts +21 -0
- package/dist/commands/whoami.js +129 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1524 -202
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-templates.d.ts +25 -0
- package/dist/lib/agent-templates.js +148 -0
- package/dist/lib/agent-templates.js.map +1 -0
- package/dist/lib/agents-config.d.ts +4 -1
- package/dist/lib/agents-config.js +19 -2
- package/dist/lib/agents-config.js.map +1 -1
- package/dist/lib/approval-poll.d.ts +42 -0
- package/dist/lib/approval-poll.js +52 -0
- package/dist/lib/approval-poll.js.map +1 -0
- package/dist/lib/auth.d.ts +29 -6
- package/dist/lib/auth.js +105 -94
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/bundle-version.d.ts +11 -0
- package/dist/lib/bundle-version.js +33 -0
- package/dist/lib/bundle-version.js.map +1 -0
- package/dist/lib/capture-lane.d.ts +67 -0
- package/dist/lib/capture-lane.js +136 -0
- package/dist/lib/capture-lane.js.map +1 -0
- package/dist/lib/cp-packages.d.ts +121 -0
- package/dist/lib/cp-packages.js +218 -0
- package/dist/lib/cp-packages.js.map +1 -0
- package/dist/lib/describe-lens.d.ts +46 -0
- package/dist/lib/describe-lens.js +33 -0
- package/dist/lib/describe-lens.js.map +1 -0
- package/dist/lib/hub-client.d.ts +84 -1
- package/dist/lib/hub-client.js +502 -22
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/installed.d.ts +51 -0
- package/dist/lib/installed.js +70 -0
- package/dist/lib/installed.js.map +1 -0
- package/dist/lib/next-steps.d.ts +61 -0
- package/dist/lib/next-steps.js +146 -0
- package/dist/lib/next-steps.js.map +1 -0
- package/dist/lib/pod.d.ts +104 -19
- package/dist/lib/pod.js +245 -57
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/project-ref.d.ts +95 -0
- package/dist/lib/project-ref.js +144 -0
- package/dist/lib/project-ref.js.map +1 -0
- package/dist/lib/project.d.ts +35 -0
- package/dist/lib/project.js +39 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/session-lens.d.ts +33 -0
- package/dist/lib/session-lens.js +76 -0
- package/dist/lib/session-lens.js.map +1 -0
- package/dist/lib/skill-import.d.ts +40 -0
- package/dist/lib/skill-import.js +203 -0
- package/dist/lib/skill-import.js.map +1 -0
- package/dist/lib/skills-installer.d.ts +16 -5
- package/dist/lib/skills-installer.js +132 -18
- package/dist/lib/skills-installer.js.map +1 -1
- package/dist/lib/suite.d.ts +28 -0
- package/dist/lib/suite.js +29 -0
- package/dist/lib/suite.js.map +1 -0
- package/dist/lib/superwhisper-import.d.ts +40 -0
- package/dist/lib/superwhisper-import.js +389 -0
- package/dist/lib/superwhisper-import.js.map +1 -0
- package/dist/lib/targets.d.ts +66 -2
- package/dist/lib/targets.js +914 -132
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/unwrapList.d.ts +1 -0
- package/dist/lib/unwrapList.js +20 -0
- package/dist/lib/unwrapList.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +10 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +10 -4
- package/skills/agent-os/SKILL.md +212 -0
- package/skills/manifest.json +5 -0
- package/skills/onboard/SKILL.md +186 -0
- package/skills/synap/SKILL.md +1524 -104
- package/skills/synap/_order.txt +37 -0
- package/skills/synap/_skill.yaml +24 -0
- package/skills/synap/authentication.md +10 -0
- package/skills/synap/automations.md +264 -0
- package/skills/synap/capabilities.md +107 -0
- package/skills/synap/capture.md +10 -0
- package/skills/synap/cli-operations.md +107 -0
- package/skills/synap/common-mistakes.md +12 -0
- package/skills/synap/creative-loop.md +43 -0
- package/skills/synap/crm.md +117 -0
- package/skills/synap/diagnostics.md +35 -0
- package/skills/synap/digesting-a-channel.md +38 -0
- package/skills/synap/document-embeds.md +123 -0
- package/skills/synap/escalation-ladder.md +71 -0
- package/skills/synap/focus-sessions.md +47 -0
- package/skills/synap/governance-rules.md +64 -0
- package/skills/synap/governance.md +6 -6
- package/skills/synap/graph-gardening.md +21 -0
- package/skills/synap/inline-patterns.md +38 -0
- package/skills/synap/lenses.md +38 -0
- package/skills/synap/linking-principle.md +39 -0
- package/skills/synap/linking.md +1 -0
- package/skills/synap/mental-model.md +45 -0
- package/skills/synap/more.md +7 -0
- package/skills/synap/multi-entity-capture.md +10 -0
- package/skills/synap/next-action.md +37 -0
- package/skills/synap/north-star.md +17 -0
- package/skills/synap/operating-mode-rules.md +45 -0
- package/skills/synap/operating-mode.md +9 -0
- package/skills/synap/quick-reference.md +67 -0
- package/skills/synap/reading.md +43 -0
- package/skills/synap/recap.md +21 -0
- package/skills/synap/reflexes.md +46 -0
- package/skills/synap/response-style.md +21 -0
- package/skills/synap/scope.md +13 -0
- package/skills/synap/showing.md +17 -0
- package/skills/synap/user-model.md +25 -0
- package/skills/synap/viewframe-cells.md +290 -0
- package/skills/synap/work-flow.md +113 -0
- package/skills/synap/worked-examples.md +53 -0
- package/skills/synap/workspace-design.md +45 -0
- package/skills/synap/workspace-edges.md +49 -0
- package/skills/synap/writes.md +156 -0
- package/skills/synap-schema/SKILL.md +97 -6
- package/skills/synap-schema/_order.txt +13 -0
- package/skills/synap-schema/_skill.yaml +22 -0
- package/skills/synap-schema/before-you-touch.md +14 -0
- package/skills/synap-schema/common-mistakes.md +9 -0
- package/skills/synap-schema/creating-profiles.md +17 -0
- package/skills/synap-schema/discover-profiles.md +24 -0
- package/skills/synap-schema/entity-scope.md +8 -0
- package/skills/synap-schema/extend-vs-create.md +31 -0
- package/skills/synap-schema/more.md +6 -0
- package/skills/synap-schema/overlay-properties.md +22 -0
- package/skills/synap-schema/profiles.md +3 -0
- package/skills/synap-schema/property-defs.md +29 -0
- package/skills/synap-schema/read-before-write.md +50 -0
- package/skills/synap-schema/relations.md +18 -0
- package/skills/synap-schema/worked-example.md +30 -0
- package/skills/synap-ui/SKILL.md +38 -11
- package/skills/synap-ui/_order.txt +13 -0
- package/skills/synap-ui/_skill.yaml +23 -0
- package/skills/synap-ui/ai-companion.md +27 -0
- package/skills/synap-ui/arranging-bento.md +8 -0
- package/skills/synap-ui/before-you-build.md +20 -0
- package/skills/synap-ui/bento-layouts.md +35 -0
- package/skills/synap-ui/common-mistakes.md +10 -0
- package/skills/synap-ui/creating-views.md +26 -0
- package/skills/synap-ui/four-builds.md +24 -0
- package/skills/synap-ui/more.md +7 -0
- package/skills/synap-ui/proposing-vs-extending.md +11 -0
- package/skills/synap-ui/view-list.md +24 -0
- package/skills/synap-ui/views.md +3 -0
- package/skills/synap-ui/worked-example.md +18 -0
- package/skills/synap-ui/workspaces.md +47 -0
- package/templates/automations/bookmark-enrichment.automation.json +44 -0
- package/templates/automations/mail-feed.automation.json +86 -0
- package/templates/automations/url-bookmark-capture.automation.json +70 -0
- package/templates/skills/README.md +21 -0
- package/templates/skills/authoring-automations/SKILL.md +95 -0
- package/templates/skills/authoring-automations/reference/node-matrix.md +49 -0
- package/templates/skills/authoring-capabilities/SKILL.md +93 -0
- package/templates/skills/authoring-capabilities/reference/template-anatomy.md +70 -0
- package/templates/skills/authoring-playbooks/SKILL.md +102 -0
- package/templates/skills/authoring-playbooks/reference/stages-contract.md +35 -0
- package/templates/skills/authoring-playbooks/reference/worked-example.md +64 -0
- package/templates/skills/bookmark-enrichment/SKILL.md +40 -0
- package/templates/skills/coordinating-agents/SKILL.md +32 -0
- package/templates/skills/coordinating-branches/SKILL.md +27 -0
- package/templates/skills/mapping-the-server/SKILL.md +54 -0
- package/templates/skills/reading-client-progress/SKILL.md +65 -0
- package/templates/skills/routing-to-channels/SKILL.md +54 -0
- package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
- package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
- package/templates/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
- package/templates/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
- package/templates/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
- package/templates/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
- package/templates/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
- package/dist/commands/finish.d.ts +0 -25
- package/dist/commands/finish.js +0 -274
- package/dist/commands/finish.js.map +0 -1
- package/dist/commands/openclaw.d.ts +0 -40
- package/dist/commands/openclaw.js +0 -1148
- package/dist/commands/openclaw.js.map +0 -1
- package/dist/commands/security-audit.d.ts +0 -12
- package/dist/commands/security-audit.js +0 -100
- package/dist/commands/security-audit.js.map +0 -1
- package/dist/lib/hardening.d.ts +0 -18
- package/dist/lib/hardening.js +0 -214
- package/dist/lib/hardening.js.map +0 -1
- package/dist/lib/templates.d.ts +0 -11
- package/dist/lib/templates.js +0 -13
- package/dist/lib/templates.js.map +0 -1
- package/dist/templates/agent-os.json +0 -3090
- package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -881
- package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -907
- package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -907
- package/node_modules/@synap/hub-rest-client/dist/index.js +0 -851
- package/node_modules/@synap/hub-rest-client/package.json +0 -45
- package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1143
- package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
- package/node_modules/@synap/hub-rest-client/src/index.ts +0 -111
- package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -77
- package/node_modules/@synap/hub-rest-client/src/types.ts +0 -639
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* synap agent ask / chat
|
|
3
|
+
*
|
|
4
|
+
* Hold a REAL conversation with the workspace's deployed Intelligence-Service
|
|
5
|
+
* agent (the orchestrator / co-founder). Unlike `synap agent run` — which hits
|
|
6
|
+
* the IS /v1/chat/completions door directly and stores a research entity — this
|
|
7
|
+
* drives the SAME channel+trigger path the browser uses, so the deployed agent
|
|
8
|
+
* answers with full workspace context, tools, and governance.
|
|
9
|
+
*
|
|
10
|
+
* Verified path (Hub Protocol REST, all under `${podUrl}/api/hub`):
|
|
11
|
+
* 1. resolve/create a WORKSPACE-scoped THREAD channel
|
|
12
|
+
* POST /threads { userId, workspaceId, title, externalSource, externalId }
|
|
13
|
+
* channelType defaults to "thread" + scope defaults to "workspace" — this is
|
|
14
|
+
* NOT the pod-wide personal channel (`/channels/personal` is pod-scoped).
|
|
15
|
+
* A stable externalId dedups, so repeated `agent ask` calls CONTINUE the
|
|
16
|
+
* same conversation (multi-turn) unless `--new` forces a fresh thread.
|
|
17
|
+
* 2. post the user turn + trigger the agent
|
|
18
|
+
* POST /threads/:id/messages { role:"user", content, userId, autoRespond:true }
|
|
19
|
+
* autoRespond enqueues an A2AI pg-boss job → IS /api/chat/stream (agentType
|
|
20
|
+
* "meta" → OrchestratorAgent). The reply is ASYNC.
|
|
21
|
+
* 3. poll for the assistant reply
|
|
22
|
+
* GET /threads/:id/messages (asc by timestamp)
|
|
23
|
+
* The a2ai worker persists the answer as a role="assistant" message. We poll
|
|
24
|
+
* until a NEW assistant message (id not seen before the post) appears.
|
|
25
|
+
*/
|
|
26
|
+
export interface AgentAskOpts {
|
|
27
|
+
message?: string;
|
|
28
|
+
workspace?: string;
|
|
29
|
+
thread?: string;
|
|
30
|
+
agentType?: string;
|
|
31
|
+
new?: boolean;
|
|
32
|
+
timeout?: string;
|
|
33
|
+
json?: boolean;
|
|
34
|
+
podUrl?: string;
|
|
35
|
+
apiKey?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface AgentChatOpts {
|
|
38
|
+
workspace?: string;
|
|
39
|
+
thread?: string;
|
|
40
|
+
agentType?: string;
|
|
41
|
+
new?: boolean;
|
|
42
|
+
timeout?: string;
|
|
43
|
+
podUrl?: string;
|
|
44
|
+
apiKey?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function agentAsk(opts: AgentAskOpts): Promise<void>;
|
|
47
|
+
export declare function agentChat(opts: AgentChatOpts): Promise<void>;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* synap agent ask / chat
|
|
3
|
+
*
|
|
4
|
+
* Hold a REAL conversation with the workspace's deployed Intelligence-Service
|
|
5
|
+
* agent (the orchestrator / co-founder). Unlike `synap agent run` — which hits
|
|
6
|
+
* the IS /v1/chat/completions door directly and stores a research entity — this
|
|
7
|
+
* drives the SAME channel+trigger path the browser uses, so the deployed agent
|
|
8
|
+
* answers with full workspace context, tools, and governance.
|
|
9
|
+
*
|
|
10
|
+
* Verified path (Hub Protocol REST, all under `${podUrl}/api/hub`):
|
|
11
|
+
* 1. resolve/create a WORKSPACE-scoped THREAD channel
|
|
12
|
+
* POST /threads { userId, workspaceId, title, externalSource, externalId }
|
|
13
|
+
* channelType defaults to "thread" + scope defaults to "workspace" — this is
|
|
14
|
+
* NOT the pod-wide personal channel (`/channels/personal` is pod-scoped).
|
|
15
|
+
* A stable externalId dedups, so repeated `agent ask` calls CONTINUE the
|
|
16
|
+
* same conversation (multi-turn) unless `--new` forces a fresh thread.
|
|
17
|
+
* 2. post the user turn + trigger the agent
|
|
18
|
+
* POST /threads/:id/messages { role:"user", content, userId, autoRespond:true }
|
|
19
|
+
* autoRespond enqueues an A2AI pg-boss job → IS /api/chat/stream (agentType
|
|
20
|
+
* "meta" → OrchestratorAgent). The reply is ASYNC.
|
|
21
|
+
* 3. poll for the assistant reply
|
|
22
|
+
* GET /threads/:id/messages (asc by timestamp)
|
|
23
|
+
* The a2ai worker persists the answer as a role="assistant" message. We poll
|
|
24
|
+
* until a NEW assistant message (id not seen before the post) appears.
|
|
25
|
+
*/
|
|
26
|
+
import chalk from "chalk";
|
|
27
|
+
import { createInterface } from "node:readline";
|
|
28
|
+
import { resolveHubConfig, resolveUserId, hubGet, hubPost, renderHubError, } from "../lib/hub-client.js";
|
|
29
|
+
import { unwrapList } from "../lib/unwrapList.js";
|
|
30
|
+
import { log } from "../utils/logger.js";
|
|
31
|
+
// ── Shared helpers ──────────────────────────────────────────────────────────────
|
|
32
|
+
/** Resolve a `--workspace <id|name>` value (or the active lens) to a workspace id. */
|
|
33
|
+
async function resolveWorkspace(cfg, wanted) {
|
|
34
|
+
// Explicit flag first — accept an id OR a name.
|
|
35
|
+
if (wanted) {
|
|
36
|
+
let list = [];
|
|
37
|
+
try {
|
|
38
|
+
const res = await hubGet("/workspaces", {}, cfg);
|
|
39
|
+
list = unwrapList(res, ["workspaces"]);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// If the list door fails, fall through and treat `wanted` as a raw id.
|
|
43
|
+
}
|
|
44
|
+
const byId = list.find((w) => String(w.id ?? "") === wanted);
|
|
45
|
+
if (byId)
|
|
46
|
+
return String(byId.id);
|
|
47
|
+
const byName = list.find((w) => String(w.name ?? "").toLowerCase() === wanted.toLowerCase());
|
|
48
|
+
if (byName)
|
|
49
|
+
return String(byName.id);
|
|
50
|
+
// No match by name; assume the caller passed a literal id.
|
|
51
|
+
return wanted;
|
|
52
|
+
}
|
|
53
|
+
// Fall back to the active lens / configured workspace.
|
|
54
|
+
if (cfg.workspaceId)
|
|
55
|
+
return cfg.workspaceId;
|
|
56
|
+
throw new Error("No workspace. Pass --workspace <id|name> or set one with `synap use <workspace>`.");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve or create the workspace-scoped THREAD channel used for this chat.
|
|
60
|
+
* Returns its id. A stable externalId keeps the conversation continuous across
|
|
61
|
+
* invocations; `--new` (or `--thread`) overrides.
|
|
62
|
+
*/
|
|
63
|
+
async function resolveChannel(cfg, userId, workspaceId, opts) {
|
|
64
|
+
if (opts.thread)
|
|
65
|
+
return opts.thread;
|
|
66
|
+
const body = {
|
|
67
|
+
userId,
|
|
68
|
+
workspaceId,
|
|
69
|
+
title: "CLI agent chat",
|
|
70
|
+
};
|
|
71
|
+
if (!opts.new) {
|
|
72
|
+
// Stable per-(user, workspace) key → POST /threads fast-path dedups on it,
|
|
73
|
+
// so successive calls reuse ONE thread and the agent sees prior turns.
|
|
74
|
+
body.externalSource = "cli";
|
|
75
|
+
body.externalId = `agent-chat:${workspaceId}`;
|
|
76
|
+
}
|
|
77
|
+
const res = (await hubPost("/threads", body, cfg));
|
|
78
|
+
if (!res?.id)
|
|
79
|
+
throw new Error("Failed to resolve chat channel (no id returned).");
|
|
80
|
+
return res.id;
|
|
81
|
+
}
|
|
82
|
+
/** Fetch all messages in a thread (asc by timestamp). */
|
|
83
|
+
async function fetchMessages(cfg, channelId) {
|
|
84
|
+
const res = await hubGet(`/threads/${channelId}/messages`, {}, cfg);
|
|
85
|
+
return unwrapList(res, ["messages"]);
|
|
86
|
+
}
|
|
87
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
88
|
+
/**
|
|
89
|
+
* Post one user turn and wait for the deployed agent's reply.
|
|
90
|
+
*
|
|
91
|
+
* @returns the assistant reply text, or null on timeout.
|
|
92
|
+
*/
|
|
93
|
+
async function sendTurnAndAwaitReply(cfg, channelId, userId, message, agentType, timeoutMs, onWait) {
|
|
94
|
+
// Snapshot the assistant messages that already exist so we can tell OUR reply
|
|
95
|
+
// apart from history — the reliable "reply is ready" signal.
|
|
96
|
+
const before = await fetchMessages(cfg, channelId);
|
|
97
|
+
const seenAssistant = new Set(before.filter((m) => m.role === "assistant").map((m) => m.id));
|
|
98
|
+
const postBody = {
|
|
99
|
+
role: "user",
|
|
100
|
+
content: message,
|
|
101
|
+
userId,
|
|
102
|
+
autoRespond: true,
|
|
103
|
+
};
|
|
104
|
+
// agentType is a forward-compat hint: the backend autoRespond door currently
|
|
105
|
+
// routes every reply to the workspace orchestrator ("meta"). Stored in metadata
|
|
106
|
+
// so a future selectable-agent door can honor it.
|
|
107
|
+
if (agentType)
|
|
108
|
+
postBody.metadata = { requestedAgentType: agentType };
|
|
109
|
+
const posted = (await hubPost(`/threads/${channelId}/messages`, postBody, cfg));
|
|
110
|
+
const userMessageId = posted?.messageId ?? "";
|
|
111
|
+
const deadline = Date.now() + timeoutMs;
|
|
112
|
+
const intervalMs = 2000;
|
|
113
|
+
while (Date.now() < deadline) {
|
|
114
|
+
await sleep(intervalMs);
|
|
115
|
+
onWait?.();
|
|
116
|
+
let msgs;
|
|
117
|
+
try {
|
|
118
|
+
msgs = await fetchMessages(cfg, channelId);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
continue; // transient — keep polling until the deadline
|
|
122
|
+
}
|
|
123
|
+
const reply = msgs.find((m) => m.role === "assistant" && !seenAssistant.has(m.id));
|
|
124
|
+
if (reply)
|
|
125
|
+
return { reply: reply.content, userMessageId };
|
|
126
|
+
}
|
|
127
|
+
return { reply: null, userMessageId };
|
|
128
|
+
}
|
|
129
|
+
function parseTimeout(raw) {
|
|
130
|
+
const secs = raw ? parseInt(raw, 10) : NaN;
|
|
131
|
+
return Number.isFinite(secs) && secs > 0 ? secs * 1000 : 90_000;
|
|
132
|
+
}
|
|
133
|
+
const TIMEOUT_HINT = "The agent did not respond in time. The Intelligence Service may be down or " +
|
|
134
|
+
"still working. Retry, or raise --timeout. Check IS health: `synap status`.";
|
|
135
|
+
// ── agent ask (single-shot) ─────────────────────────────────────────────────────
|
|
136
|
+
export async function agentAsk(opts) {
|
|
137
|
+
const message = (opts.message ?? "").trim();
|
|
138
|
+
if (!message) {
|
|
139
|
+
console.error(chalk.red("Error: a message is required. Usage: synap agent ask \"your message\""));
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const cfg = await resolveHubConfig(opts);
|
|
144
|
+
const userId = await resolveUserId(cfg);
|
|
145
|
+
const workspaceId = await resolveWorkspace(cfg, opts.workspace);
|
|
146
|
+
const channelId = await resolveChannel(cfg, userId, workspaceId, opts);
|
|
147
|
+
const timeoutMs = parseTimeout(opts.timeout);
|
|
148
|
+
if (!opts.json) {
|
|
149
|
+
log.dim(`workspace ${workspaceId} · thread ${channelId}`);
|
|
150
|
+
process.stdout.write(chalk.dim(" waiting for agent"));
|
|
151
|
+
}
|
|
152
|
+
const { reply } = await sendTurnAndAwaitReply(cfg, channelId, userId, message, opts.agentType, timeoutMs, () => {
|
|
153
|
+
if (!opts.json)
|
|
154
|
+
process.stdout.write(chalk.dim("."));
|
|
155
|
+
});
|
|
156
|
+
if (!opts.json)
|
|
157
|
+
process.stdout.write("\n");
|
|
158
|
+
if (reply === null) {
|
|
159
|
+
if (opts.json) {
|
|
160
|
+
console.log(JSON.stringify({ ok: false, error: "timeout", workspaceId, threadId: channelId }, null, 2));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
log.error(TIMEOUT_HINT);
|
|
164
|
+
}
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
if (opts.json) {
|
|
168
|
+
console.log(JSON.stringify({ ok: true, reply, workspaceId, threadId: channelId }, null, 2));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
log.blank();
|
|
172
|
+
console.log(chalk.green(" agent") + chalk.dim(" ▸"));
|
|
173
|
+
console.log(reply.split("\n").map((l) => " " + l).join("\n"));
|
|
174
|
+
log.blank();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
if (opts.json) {
|
|
179
|
+
console.log(JSON.stringify({ ok: false, error: e.message }, null, 2));
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
renderHubError(e);
|
|
183
|
+
}
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// ── agent chat (interactive REPL) ────────────────────────────────────────────────
|
|
188
|
+
export async function agentChat(opts) {
|
|
189
|
+
let cfg;
|
|
190
|
+
let userId;
|
|
191
|
+
let workspaceId;
|
|
192
|
+
let channelId;
|
|
193
|
+
const timeoutMs = parseTimeout(opts.timeout);
|
|
194
|
+
try {
|
|
195
|
+
cfg = await resolveHubConfig(opts);
|
|
196
|
+
userId = await resolveUserId(cfg);
|
|
197
|
+
workspaceId = await resolveWorkspace(cfg, opts.workspace);
|
|
198
|
+
channelId = await resolveChannel(cfg, userId, workspaceId, opts);
|
|
199
|
+
}
|
|
200
|
+
catch (e) {
|
|
201
|
+
renderHubError(e);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
log.heading("Synap agent chat");
|
|
206
|
+
log.dim(`workspace ${workspaceId} · thread ${channelId}`);
|
|
207
|
+
log.dim("Type your message and press enter. /exit or Ctrl-D to quit.");
|
|
208
|
+
log.blank();
|
|
209
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
210
|
+
const prompt = () => rl.setPrompt(chalk.cyan("you ▸ "));
|
|
211
|
+
prompt();
|
|
212
|
+
rl.prompt();
|
|
213
|
+
rl.on("line", async (line) => {
|
|
214
|
+
const message = line.trim();
|
|
215
|
+
if (!message) {
|
|
216
|
+
rl.prompt();
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (message === "/exit" || message === "/quit") {
|
|
220
|
+
rl.close();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
rl.pause();
|
|
224
|
+
process.stdout.write(chalk.dim(" waiting for agent"));
|
|
225
|
+
try {
|
|
226
|
+
const { reply } = await sendTurnAndAwaitReply(cfg, channelId, userId, message, opts.agentType, timeoutMs, () => process.stdout.write(chalk.dim(".")));
|
|
227
|
+
process.stdout.write("\n");
|
|
228
|
+
if (reply === null) {
|
|
229
|
+
log.error(TIMEOUT_HINT);
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
console.log(chalk.green("agent ▸"));
|
|
233
|
+
console.log(reply.split("\n").map((l) => " " + l).join("\n"));
|
|
234
|
+
log.blank();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
process.stdout.write("\n");
|
|
239
|
+
log.error(e.message);
|
|
240
|
+
}
|
|
241
|
+
rl.resume();
|
|
242
|
+
rl.prompt();
|
|
243
|
+
});
|
|
244
|
+
rl.on("close", () => {
|
|
245
|
+
log.blank();
|
|
246
|
+
log.dim("Chat ended.");
|
|
247
|
+
process.exit(0);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=agent-chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-chat.js","sourceRoot":"","sources":["../../src/commands/agent-chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,MAAM,EACN,OAAO,EAEP,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAkCzC,mFAAmF;AAEnF,sFAAsF;AACtF,KAAK,UAAU,gBAAgB,CAC7B,GAAc,EACd,MAA0B;IAE1B,gDAAgD;IAChD,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,IAAI,GAAmC,EAAE,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;YACjD,IAAI,GAAG,UAAU,CAA0B,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;QACzE,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC;QAC7D,IAAI,IAAI;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CACtB,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CACnE,CAAC;QACF,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrC,2DAA2D;QAC3D,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,uDAAuD;IACvD,IAAI,GAAG,CAAC,WAAW;QAAE,OAAO,GAAG,CAAC,WAAW,CAAC;IAC5C,MAAM,IAAI,KAAK,CACb,mFAAmF,CACpF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,cAAc,CAC3B,GAAc,EACd,MAAc,EACd,WAAmB,EACnB,IAAwC;IAExC,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC;IAEpC,MAAM,IAAI,GAA4B;QACpC,MAAM;QACN,WAAW;QACX,KAAK,EAAE,gBAAgB;KACxB,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACd,2EAA2E;QAC3E,uEAAuE;QACvE,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,UAAU,GAAG,cAAc,WAAW,EAAE,CAAC;IAChD,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,CAAoB,CAAC;IACtE,IAAI,CAAC,GAAG,EAAE,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IAClF,OAAO,GAAG,CAAC,EAAE,CAAC;AAChB,CAAC;AAED,yDAAyD;AACzD,KAAK,UAAU,aAAa,CAC1B,GAAc,EACd,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,YAAY,SAAS,WAAW,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IACpE,OAAO,UAAU,CAAc,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpE;;;;GAIG;AACH,KAAK,UAAU,qBAAqB,CAClC,GAAc,EACd,SAAiB,EACjB,MAAc,EACd,OAAe,EACf,SAA6B,EAC7B,SAAiB,EACjB,MAAmB;IAEnB,8EAA8E;IAC9E,6DAA6D;IAC7D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAC9D,CAAC;IAEF,MAAM,QAAQ,GAA4B;QACxC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,OAAO;QAChB,MAAM;QACN,WAAW,EAAE,IAAI;KAClB,CAAC;IACF,6EAA6E;IAC7E,gFAAgF;IAChF,kDAAkD;IAClD,IAAI,SAAS;QAAE,QAAQ,CAAC,QAAQ,GAAG,EAAE,kBAAkB,EAAE,SAAS,EAAE,CAAC;IAErE,MAAM,MAAM,GAAG,CAAC,MAAM,OAAO,CAC3B,YAAY,SAAS,WAAW,EAChC,QAAQ,EACR,GAAG,CACJ,CAA2B,CAAC;IAC7B,MAAM,aAAa,GAAG,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC;IAE9C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC;IACxB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC;QACxB,MAAM,EAAE,EAAE,CAAC;QACX,IAAI,IAAmB,CAAC;QACxB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,8CAA8C;QAC1D,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CACrB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAC1D,CAAC;QACF,IAAI,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;IAC5D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,YAAY,CAAC,GAAuB;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC3C,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAClE,CAAC;AAED,MAAM,YAAY,GAChB,6EAA6E;IAC7E,4EAA4E,CAAC;AAE/E,mFAAmF;AAEnF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAkB;IAC/C,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAChE,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QACvE,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAE7C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,GAAG,CAAC,GAAG,CAAC,aAAa,WAAW,eAAe,SAAS,EAAE,CAAC,CAAC;YAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,qBAAqB,CAC3C,GAAG,EACH,SAAS,EACT,MAAM,EACN,OAAO,EACP,IAAI,CAAC,SAAS,EACd,SAAS,EACT,GAAG,EAAE;YACH,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QACvD,CAAC,CACF,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE3C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,EACjE,IAAI,EACJ,CAAC,CACF,CACF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAC1B,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,EACrD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/D,GAAG,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAG,CAAW,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACnF,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,oFAAoF;AAEpF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,IAAI,GAAc,CAAC;IACnB,IAAI,MAAc,CAAC;IACnB,IAAI,WAAmB,CAAC;IACxB,IAAI,SAAiB,CAAC;IACtB,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;QAClC,WAAW,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1D,SAAS,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,cAAc,CAAC,CAAC,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChC,GAAG,CAAC,GAAG,CAAC,aAAa,WAAW,eAAe,SAAS,EAAE,CAAC,CAAC;IAC5D,GAAG,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;IACvE,GAAG,CAAC,KAAK,EAAE,CAAC;IAEZ,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC;IACT,EAAE,CAAC,MAAM,EAAE,CAAC;IAEZ,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,EAAE,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QACD,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YAC/C,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QACD,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,qBAAqB,CAC3C,GAAG,EACH,SAAS,EACT,MAAM,EACN,OAAO,EACP,IAAI,CAAC,SAAS,EACd,SAAS,EACT,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAC3C,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/D,GAAG,CAAC,KAAK,EAAE,CAAC;YACd,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,GAAG,CAAC,KAAK,CAAE,CAAW,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;QACD,EAAE,CAAC,MAAM,EAAE,CAAC;QACZ,EAAE,CAAC,MAAM,EAAE,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAClB,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACvB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* synap agent run / schedule / tick
|
|
3
|
+
*
|
|
4
|
+
* The CLI is a thin trigger. The IS handles all reasoning and tool execution
|
|
5
|
+
* server-side via MCP. The CLI's responsibilities are:
|
|
6
|
+
* 1. Resolve which agent (and its pod/workspace) to use
|
|
7
|
+
* 2. Send the goal to IS /v1/chat/completions
|
|
8
|
+
* 3. Store the final output as a `research` entity on the pod
|
|
9
|
+
* 4. Display the result
|
|
10
|
+
*
|
|
11
|
+
* Schedules are stored as `task` entities on the pod (not local files) so they
|
|
12
|
+
* are visible in pod-admin and shareable across machines.
|
|
13
|
+
* `synap agent tick` reads due schedules from the pod and fires them.
|
|
14
|
+
* Wire it to the pod server's crontab for autonomous execution.
|
|
15
|
+
*/
|
|
16
|
+
type Persona = "researcher" | "assistant" | "developer";
|
|
17
|
+
export interface RunOpts {
|
|
18
|
+
goal: string;
|
|
19
|
+
persona?: Persona;
|
|
20
|
+
model?: string;
|
|
21
|
+
workspace?: string;
|
|
22
|
+
maxTokens?: number;
|
|
23
|
+
dryRun?: boolean;
|
|
24
|
+
podUrl?: string;
|
|
25
|
+
apiKey?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ScheduleOpts {
|
|
28
|
+
goal?: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
persona?: Persona;
|
|
31
|
+
model?: string;
|
|
32
|
+
workspace?: string;
|
|
33
|
+
every?: "hourly" | "daily" | "weekly";
|
|
34
|
+
list?: boolean;
|
|
35
|
+
remove?: string;
|
|
36
|
+
runNow?: boolean;
|
|
37
|
+
podUrl?: string;
|
|
38
|
+
apiKey?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function agentRun(opts: RunOpts): Promise<void>;
|
|
41
|
+
export declare function agentSchedule(opts: ScheduleOpts): Promise<void>;
|
|
42
|
+
export declare function agentTick(opts: {
|
|
43
|
+
dryRun?: boolean;
|
|
44
|
+
podUrl?: string;
|
|
45
|
+
apiKey?: string;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* synap agent run / schedule / tick
|
|
3
|
+
*
|
|
4
|
+
* The CLI is a thin trigger. The IS handles all reasoning and tool execution
|
|
5
|
+
* server-side via MCP. The CLI's responsibilities are:
|
|
6
|
+
* 1. Resolve which agent (and its pod/workspace) to use
|
|
7
|
+
* 2. Send the goal to IS /v1/chat/completions
|
|
8
|
+
* 3. Store the final output as a `research` entity on the pod
|
|
9
|
+
* 4. Display the result
|
|
10
|
+
*
|
|
11
|
+
* Schedules are stored as `task` entities on the pod (not local files) so they
|
|
12
|
+
* are visible in pod-admin and shareable across machines.
|
|
13
|
+
* `synap agent tick` reads due schedules from the pod and fires them.
|
|
14
|
+
* Wire it to the pod server's crontab for autonomous execution.
|
|
15
|
+
*/
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
import ora from "ora";
|
|
18
|
+
import { resolveHubConfig, hubGet, hubPost, hubPatch } from "../lib/hub-client.js";
|
|
19
|
+
import { unwrapList } from "../lib/unwrapList.js";
|
|
20
|
+
import { log } from "../utils/logger.js";
|
|
21
|
+
// ── Persona system prompts ────────────────────────────────────────────────────
|
|
22
|
+
// Injected as the system message. The IS handles tool use via MCP.
|
|
23
|
+
const PERSONAS = {
|
|
24
|
+
researcher: "You are a research agent. Investigate the given goal thoroughly using all available tools " +
|
|
25
|
+
"(web search, URL fetch, memory recall, entity search). Capture findings as you go. " +
|
|
26
|
+
"When you have a complete synthesis, produce a clear final answer.",
|
|
27
|
+
assistant: "You are a helpful assistant. Complete the given task using all available tools. " +
|
|
28
|
+
"Produce a clear, actionable final answer.",
|
|
29
|
+
developer: "You are a software engineering agent. Analyze the task, recall relevant knowledge, " +
|
|
30
|
+
"reason carefully, and produce a technical conclusion or recommendation.",
|
|
31
|
+
};
|
|
32
|
+
async function callIS(podUrl, apiKey, model, messages, maxTokens) {
|
|
33
|
+
const res = await fetch(`${podUrl}/v1/chat/completions`, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: `Bearer ${apiKey}`,
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify({ model, messages, max_tokens: maxTokens }),
|
|
40
|
+
signal: AbortSignal.timeout(180_000),
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
const body = await res.text().catch(() => "");
|
|
44
|
+
throw new Error(`IS error (HTTP ${res.status}): ${body.slice(0, 300)}`);
|
|
45
|
+
}
|
|
46
|
+
return res.json();
|
|
47
|
+
}
|
|
48
|
+
async function storeResearch(title, content, tags, cfg) {
|
|
49
|
+
const res = await hubPost("/entities", {
|
|
50
|
+
userId: cfg.userId,
|
|
51
|
+
workspaceId: cfg.workspaceId,
|
|
52
|
+
profileSlug: "research",
|
|
53
|
+
name: title,
|
|
54
|
+
properties: { summary: content, tags, status: "concluded" },
|
|
55
|
+
}, cfg);
|
|
56
|
+
return res.id;
|
|
57
|
+
}
|
|
58
|
+
// ── Schedule helpers ──────────────────────────────────────────────────────────
|
|
59
|
+
const INTERVAL_MS = {
|
|
60
|
+
hourly: 60 * 60 * 1000,
|
|
61
|
+
daily: 24 * 60 * 60 * 1000,
|
|
62
|
+
weekly: 7 * 24 * 60 * 60 * 1000,
|
|
63
|
+
};
|
|
64
|
+
async function listScheduleEntities(cfg) {
|
|
65
|
+
const res = await hubGet("/entities", { q: "[agent-sched]", workspaceId: cfg.workspaceId, limit: "50" }, cfg);
|
|
66
|
+
const entities = unwrapList(res, ["entities"]);
|
|
67
|
+
return entities.filter((e) => e.name?.startsWith("[agent-sched]"));
|
|
68
|
+
}
|
|
69
|
+
// ── Public: agentRun ──────────────────────────────────────────────────────────
|
|
70
|
+
export async function agentRun(opts) {
|
|
71
|
+
const goal = opts.goal?.trim();
|
|
72
|
+
if (!goal) {
|
|
73
|
+
log.error("--goal is required.");
|
|
74
|
+
log.dim('Example: synap agent run --goal "Research RAG architectures"');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const persona = opts.persona ?? "researcher";
|
|
78
|
+
const model = opts.model ?? "synap/balanced";
|
|
79
|
+
const maxTokens = opts.maxTokens ?? 4000;
|
|
80
|
+
let cfg;
|
|
81
|
+
try {
|
|
82
|
+
cfg = await resolveHubConfig({ podUrl: opts.podUrl, apiKey: opts.apiKey });
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
log.error(err.message);
|
|
86
|
+
log.dim("Run `synap pods add` to configure a pod, or pass --pod-url and --api-key.");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const workspaceId = opts.workspace ?? cfg.workspaceId;
|
|
90
|
+
const runCfg = { ...cfg, workspaceId };
|
|
91
|
+
if (opts.dryRun) {
|
|
92
|
+
log.heading("Agent run — dry run");
|
|
93
|
+
console.log();
|
|
94
|
+
console.log(` ${chalk.dim("goal")} ${chalk.bold(goal)}`);
|
|
95
|
+
console.log(` ${chalk.dim("persona")} ${chalk.cyan(persona)}`);
|
|
96
|
+
console.log(` ${chalk.dim("model")} ${chalk.cyan(model)}`);
|
|
97
|
+
console.log(` ${chalk.dim("pod")} ${chalk.underline(cfg.podUrl)}`);
|
|
98
|
+
console.log(` ${chalk.dim("workspace")} ${workspaceId ? chalk.underline(workspaceId) : chalk.yellow("none — entities will be pod-global")}`);
|
|
99
|
+
console.log();
|
|
100
|
+
log.dim(`Will POST to: ${cfg.podUrl}/v1/chat/completions`);
|
|
101
|
+
log.dim("Remove --dry-run to execute.");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
log.heading(`Agent run — ${chalk.bold(persona)}`);
|
|
105
|
+
log.dim(`Goal: ${goal}`);
|
|
106
|
+
log.dim(`Model: ${model} · Pod: ${cfg.podUrl}`);
|
|
107
|
+
console.log();
|
|
108
|
+
const spinner = ora({ text: "Calling IS…", color: "cyan" }).start();
|
|
109
|
+
const start = Date.now();
|
|
110
|
+
let response;
|
|
111
|
+
try {
|
|
112
|
+
response = await callIS(cfg.podUrl, cfg.apiKey, model, [
|
|
113
|
+
{ role: "system", content: PERSONAS[persona] },
|
|
114
|
+
{ role: "user", content: goal },
|
|
115
|
+
], maxTokens);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const msg = err.message;
|
|
119
|
+
spinner.fail(chalk.red("IS call failed"));
|
|
120
|
+
console.log();
|
|
121
|
+
log.error(msg);
|
|
122
|
+
if (msg.includes("403") && msg.toLowerCase().includes("scope")) {
|
|
123
|
+
log.warn("Your CLI key is missing a required scope.");
|
|
124
|
+
log.dim("Fix: run synap connect to rotate your key with the updated scope list.");
|
|
125
|
+
log.dim("Or in pod-admin → Trust & Keys, delete your CLI key and reconnect.");
|
|
126
|
+
}
|
|
127
|
+
else if (msg.includes("IS error")) {
|
|
128
|
+
log.dim(`Verify the IS is running: curl ${cfg.podUrl}/v1/models -H "Authorization: Bearer <key>"`);
|
|
129
|
+
}
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
const content = response.choices?.[0]?.message?.content ?? "";
|
|
133
|
+
const elapsed = ((Date.now() - start) / 1000).toFixed(1);
|
|
134
|
+
spinner.text = "Storing result…";
|
|
135
|
+
let entityId;
|
|
136
|
+
try {
|
|
137
|
+
entityId = await storeResearch(`Agent run: ${goal.slice(0, 80)}`, content, ["agent-run", persona], runCfg);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// storage failure is non-fatal — still display the result
|
|
141
|
+
}
|
|
142
|
+
spinner.succeed(chalk.green(`Done · ${elapsed}s`));
|
|
143
|
+
console.log();
|
|
144
|
+
if (entityId) {
|
|
145
|
+
log.success(`Research stored → ${chalk.underline(`${cfg.podUrl}/admin/entities/${entityId}`)}`);
|
|
146
|
+
console.log();
|
|
147
|
+
}
|
|
148
|
+
if (content) {
|
|
149
|
+
log.heading("Result");
|
|
150
|
+
console.log(chalk.white(content.trim()));
|
|
151
|
+
console.log();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ── Public: agentSchedule ─────────────────────────────────────────────────────
|
|
155
|
+
export async function agentSchedule(opts) {
|
|
156
|
+
let cfg;
|
|
157
|
+
try {
|
|
158
|
+
cfg = await resolveHubConfig({ podUrl: opts.podUrl, apiKey: opts.apiKey });
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
log.error(err.message);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
// List
|
|
165
|
+
if (opts.list) {
|
|
166
|
+
const schedules = await listScheduleEntities(cfg);
|
|
167
|
+
if (schedules.length === 0) {
|
|
168
|
+
log.warn("No schedules found on this pod/workspace.");
|
|
169
|
+
log.dim("Add one: synap agent schedule --goal '...' --name <name> --every daily");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
log.heading(`Agent schedules (${schedules.length})`);
|
|
173
|
+
for (const s of schedules) {
|
|
174
|
+
const p = s.properties;
|
|
175
|
+
const badge = p.enabled ? chalk.green("●") : chalk.red("○");
|
|
176
|
+
const last = p.lastRunAt ? `last ran ${new Date(p.lastRunAt).toLocaleString()}` : "never ran";
|
|
177
|
+
const next = new Date(p.nextRunAt).toLocaleString();
|
|
178
|
+
console.log(` ${badge} ${chalk.bold(s.name.replace("[agent-sched] ", "").padEnd(24))} ${chalk.cyan(p.interval.padEnd(8))} ${chalk.dim(last)}`);
|
|
179
|
+
console.log(` next: ${chalk.dim(next)} | goal: ${chalk.dim(p.goal.slice(0, 70))}`);
|
|
180
|
+
}
|
|
181
|
+
console.log();
|
|
182
|
+
log.dim("Run due schedules now: synap agent tick");
|
|
183
|
+
log.dim("Crontab (daily at 09:00): 0 9 * * * synap agent tick");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// Remove
|
|
187
|
+
if (opts.remove) {
|
|
188
|
+
const schedules = await listScheduleEntities(cfg);
|
|
189
|
+
const target = schedules.find((s) => s.name === `[agent-sched] ${opts.remove}` || s.name === opts.remove);
|
|
190
|
+
if (!target) {
|
|
191
|
+
log.error(`No schedule named "${opts.remove}" found.`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
// Disable it (soft delete — PATCH enabled=false)
|
|
195
|
+
await hubPatch(`/entities/${target.id}`, { properties: { ...target.properties, enabled: false } }, cfg);
|
|
196
|
+
log.info(`Disabled schedule: ${chalk.bold(opts.remove)}`);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Add
|
|
200
|
+
const { goal, name, every } = opts;
|
|
201
|
+
if (!goal?.trim() || !name?.trim() || !every) {
|
|
202
|
+
log.error("Required: --goal, --name, --every (hourly|daily|weekly)");
|
|
203
|
+
log.dim('Example: synap agent schedule --goal "Research AI news" --name daily-ai --every daily');
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
const existing = await listScheduleEntities(cfg).catch(() => []);
|
|
207
|
+
if (existing.find((s) => s.name === `[agent-sched] ${name}`)) {
|
|
208
|
+
log.error(`A schedule named "${name}" already exists.`);
|
|
209
|
+
log.dim(`Remove it first: synap agent schedule --remove ${name}`);
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
const now = new Date().toISOString();
|
|
213
|
+
await hubPost("/entities", {
|
|
214
|
+
userId: cfg.userId,
|
|
215
|
+
workspaceId: cfg.workspaceId,
|
|
216
|
+
profileSlug: "task",
|
|
217
|
+
name: `[agent-sched] ${name}`,
|
|
218
|
+
properties: {
|
|
219
|
+
goal: goal.trim(),
|
|
220
|
+
persona: opts.persona ?? "researcher",
|
|
221
|
+
model: opts.model ?? "synap/balanced",
|
|
222
|
+
interval: every,
|
|
223
|
+
intervalMs: INTERVAL_MS[every],
|
|
224
|
+
nextRunAt: now,
|
|
225
|
+
enabled: true,
|
|
226
|
+
createdAt: now,
|
|
227
|
+
},
|
|
228
|
+
}, cfg);
|
|
229
|
+
log.info(`Schedule created: ${chalk.bold(name)} — runs ${chalk.cyan(every)}`);
|
|
230
|
+
console.log();
|
|
231
|
+
const cron = every === "hourly" ? "0 * * * *" : every === "daily" ? "0 9 * * *" : "0 9 * * 1";
|
|
232
|
+
log.dim(`Add to pod server crontab: ${cron} synap agent tick`);
|
|
233
|
+
if (opts.runNow) {
|
|
234
|
+
console.log();
|
|
235
|
+
await agentRun({
|
|
236
|
+
goal: goal.trim(),
|
|
237
|
+
persona: opts.persona,
|
|
238
|
+
model: opts.model,
|
|
239
|
+
workspace: opts.workspace ?? cfg.workspaceId,
|
|
240
|
+
podUrl: opts.podUrl,
|
|
241
|
+
apiKey: opts.apiKey,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// ── Public: agentTick ─────────────────────────────────────────────────────────
|
|
246
|
+
export async function agentTick(opts) {
|
|
247
|
+
let cfg;
|
|
248
|
+
try {
|
|
249
|
+
cfg = await resolveHubConfig({ podUrl: opts.podUrl, apiKey: opts.apiKey });
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
log.error(err.message);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
const schedules = await listScheduleEntities(cfg).catch(() => []);
|
|
256
|
+
const enabled = schedules.filter((s) => s.properties.enabled);
|
|
257
|
+
if (enabled.length === 0) {
|
|
258
|
+
log.dim("No enabled schedules on this pod.");
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const now = Date.now();
|
|
262
|
+
const due = enabled.filter((s) => {
|
|
263
|
+
const next = new Date(s.properties.nextRunAt).getTime();
|
|
264
|
+
return now >= next;
|
|
265
|
+
});
|
|
266
|
+
if (due.length === 0) {
|
|
267
|
+
const next = enabled
|
|
268
|
+
.map((s) => new Date(s.properties.nextRunAt).getTime())
|
|
269
|
+
.sort((a, b) => a - b)[0];
|
|
270
|
+
log.dim(`No schedules due. Next: ${new Date(next).toLocaleString()}`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
log.heading(`Ticking ${due.length} due schedule(s)`);
|
|
274
|
+
for (const s of due) {
|
|
275
|
+
const p = s.properties;
|
|
276
|
+
log.info(`Running: ${chalk.bold(s.name.replace("[agent-sched] ", ""))}`);
|
|
277
|
+
if (opts.dryRun) {
|
|
278
|
+
log.dim(` [dry-run] goal: ${p.goal.slice(0, 70)}`);
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
await agentRun({
|
|
283
|
+
goal: p.goal,
|
|
284
|
+
persona: p.persona,
|
|
285
|
+
model: p.model,
|
|
286
|
+
workspace: cfg.workspaceId,
|
|
287
|
+
podUrl: opts.podUrl,
|
|
288
|
+
apiKey: opts.apiKey,
|
|
289
|
+
});
|
|
290
|
+
const nextRunAt = new Date(now + p.intervalMs).toISOString();
|
|
291
|
+
await hubPatch(`/entities/${s.id}`, { properties: { ...p, lastRunAt: new Date(now).toISOString(), nextRunAt } }, cfg).catch(() => {
|
|
292
|
+
// non-fatal — schedule ran, just couldn't update nextRunAt
|
|
293
|
+
log.dim(` Warning: could not update nextRunAt for "${s.name}" on the pod.`);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
log.error(`Schedule "${s.name}" failed: ${err.message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=agent-run.js.map
|