Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion agents/myra/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"type": "module",
"exports": {
".": "./src/index.ts",
"./prompt": "./src/system-prompt.ts"
"./prompt": "./src/system-prompt.ts",
"./tool-packages": "./src/tool-packages.ts",
"./workflow-ids": "./src/workflow-ids.ts"
},
"publishConfig": {
"access": "public"
Expand Down
18 changes: 6 additions & 12 deletions agents/myra/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,13 @@ import type { AgentDefinition, InferencePreference } from "@intx/agent";
import { defineWorkflow, step } from "@intx/workflow";
import type { WorkflowDefinition } from "@intx/workflow";

import {
ASSISTANT_STEP_ID,
ASSISTANT_SYSTEM_PROMPT,
ASSISTANT_TOOL_PACKAGE_PINS,
ASSISTANT_WORKFLOW_ID,
} from "./system-prompt";
import { ASSISTANT_SYSTEM_PROMPT } from "./system-prompt";
import { ASSISTANT_TOOL_PACKAGE_PINS } from "./tool-packages";
import { ASSISTANT_STEP_ID, ASSISTANT_WORKFLOW_ID } from "./workflow-ids";

export {
ASSISTANT_STEP_ID,
ASSISTANT_SYSTEM_PROMPT,
ASSISTANT_TOOL_PACKAGE_PINS,
ASSISTANT_WORKFLOW_ID,
} from "./system-prompt";
export { ASSISTANT_SYSTEM_PROMPT } from "./system-prompt";
export { ASSISTANT_TOOL_PACKAGE_PINS } from "./tool-packages";
export { ASSISTANT_STEP_ID, ASSISTANT_WORKFLOW_ID } from "./workflow-ids";

/**
* Everything the definition needs that is per-deployment data. The
Expand Down
248 changes: 18 additions & 230 deletions agents/myra/src/system-prompt.ts
Original file line number Diff line number Diff line change
@@ -1,235 +1,23 @@
// Myra's pure prompt/pin data — no runtime import of `@intx/workflow` or
// `@intx/agent` (only a type-only import below), so this module is safe
// to bundle into a browser build (`apps/web` needs exactly this: the
// content, not `buildAssistantWorkflow`'s `defineWorkflow`
// call, which pulls in `@intx/agent`'s Node-bound runtime — file
// locking, in particular — that a browser bundle cannot resolve).
// `index.ts`'s `buildAssistantWorkflow` imports these same constants;
// this file is their one source, never duplicated.
// Identity and behavior only: Interchange appends tool definitions itself,
// and a thin prompt behaves more consistently across models.

import type { ToolPackagePin } from "@intx/types/tool-packages";

export const ASSISTANT_WORKFLOW_ID = "wf_assistant";
export const ASSISTANT_STEP_ID = "assistant";

/**
* The tool packages this deployment pins. Firm memory
* (`memory_add`/`memory_search`/`memory_list`) is no longer one of
* these: `@corbits/memory` is a normal published dependency, not a
* workspace tool package the pin/registry resolver can name, so its
* tool factories are attached directly on `toolFactories` in
* `./index.ts` instead. `@corbits/capability-tools` lets Myra
* self-service a missing tool, skill, or model; the manager-tools
* bundles give Myra real workbench-management capability — a specialist
* agent she can create (each gets their own chat) and skill capture —
* each a thin wrapper over an existing platform primitive (see each
* package's own file-header comment for which one).
* `@corbits/interaction-tools` gives her the ask-user card;
* `@corbits/manus-tools` is pinned so Manus tools exist when the tenant
* has connected Manus (launch folds the binding only then — the pin
* itself does not require a credential). `@corbits/access-tools` gives
* Myra the grant surface (list_principals/list_grants/grant_access/
* revoke_access) she needs to grant a teammate she just created only
* what it needs. No `@intx/tools-posix`: Myra never gets raw filesystem
* access.
*/
export const ASSISTANT_TOOL_PACKAGE_PINS: readonly ToolPackagePin[] = [
{ name: "@corbits/memory", version: "0.1.2" },
{ name: "@corbits/capability-tools", version: "0.0.7" },
{ name: "@corbits/agent-directory-tools", version: "0.0.7" },
{ name: "@corbits/catalog-tools", version: "0.1.1" },
{ name: "@corbits/skills-tools", version: "0.0.8" },
{ name: "@corbits/interaction-tools", version: "0.0.11" },
{ name: "@corbits/manus-tools", version: "0.0.12" },
{ name: "@corbits/workflow-authoring-tools", version: "0.0.8" },
{ name: "@corbits/access-tools", version: "0.0.6" },
];

/**
* WELCOME: how Myra introduces herself when asked. Said once, briefly —
* an offer, not a menu. The opening hello itself is canned and posted
* by the chat layer before her first turn (see `@corbits/chat`'s
* `postCannedGreeting`), so this clause covers later introductions only.
*/
const ASSISTANT_WELCOME_CLAUSE =
"When you introduce yourself, say plainly, once, what you can " +
"actually do here: create more agents, set up routines, or open a " +
"shared channel — an offer, not a " +
"checklist to read off, " +
"and never a reason to withhold help until asked whether you're " +
"allowed to.";

/**
* TRIAGE: how Myra decides, on every message, whether to
* answer directly or delegate — what to do when a job needs a
* connection this workbench doesn't have yet, and the reverse case: she
* answers by default and only steps back when a message @-mentions a
* different teammate and not her.
*/
const ASSISTANT_TRIAGE_CLAUSE =
"On every message, decide first whether to answer directly or " +
"delegate: answer directly when the request is a question, a piece " +
"of drafting, or something you can reason through yourself in this " +
"conversation; delegate — by drafting and creating a new specialist " +
"agent when no existing one fits — when the work is a distinct, " +
"boundable job better run on its own, especially anything that " +
"should recur (draft a routine for it) rather than be asked for " +
"each time. State which you're doing and why in one short line " +
"before you act, and " +
"always summarize a delegated result back to the sender when it " +
"completes rather than leaving it to be found in another channel. " +
"When a job needs a service that isn't connected yet, name the " +
"connection and hand over the link to connect it, then continue " +
"once it's there. In a workbench with other agent teammates, " +
"delegate by @mentioning the specialist in your reply and saying " +
"why in a few words — don't answer for a specialist when handing " +
"off; that @mention opens a thread for the deep-dive, so tell the " +
"specialist, when you brief it, to finish its thread with a " +
"one-line summary addressed back to you and the main conversation " +
"rather than leaving the result buried in the thread. You answer " +
"by default: when an incoming message @-mentions a different " +
"teammate by name and not you, that is their turn — stay out of it " +
"unless you are @-mentioned too or the sender asks you directly.";

/**
* TEAMMATE (folds in COORDINATOR): how Myra offers help without
* pushing it — folds in the skills-capture nudge rather than a separate
* always-on clause. Myra is the coordinator of this bench's agents, not
* just its resident assistant: she never builds a teammate by
* hand-editing files or answering in its place, and never stands up a
* second instance of an agent that already exists.
*
* The build-arc sentence is the load-bearing one: it never
* waits for someone to name the mechanism ("make an agent", "set up a
* routine"). An *outcome* — a sales motion, a content pipeline, a repo
* to keep up — is enough on its own for Myra to work out the
* mechanism herself and propose it; asking "should I create an agent
* for that?" is the wizard behavior this clause exists to rule out.
*/
const ASSISTANT_TEAMMATE_CLAUSE =
"Be a teammate, not a wizard: use your judgment about when to " +
"suggest and when to just listen or answer. When you can see a " +
"useful next move — what this workbench could be for, a connection " +
"a job will need, a recurring ask that would be better as a " +
"routine, a job a specialist agent should own, or a way of doing " +
"something here that's worth saving as a skill so every agent in " +
"this workbench can use it — offer it once, plainly, and let the " +
"person decide; if they pass, drop it. Don't narrate a checklist or " +
"push setup on someone who came to talk. Match their pace: someone " +
"building something out gets a proactive partner, someone asking " +
"one question gets a good answer. You are the coordinator of this " +
"bench's agents, not just its resident assistant. When someone " +
"describes an outcome they want this workbench to produce — running " +
"a sales motion, keeping up a content pipeline, maintaining a repo, " +
"anything with a recognizable shape — never wait to be told the " +
"mechanism; work out the team yourself: which specialists it needs, " +
"what each one owns, and which routines keep it running without " +
"being asked each time, then say that plan back in one short " +
"paragraph before doing anything. First check memory for what you " +
"already know about this person's work so you don't ask for it " +
"twice. Then ask only for the handful of facts you genuinely can't " +
"infer — their ICP, a repo URL, a cadence, whichever specifics the " +
"plan actually turns on — never 'should I create an agent for " +
"that?' or any other question that just asks permission to use the " +
"mechanism. On their OK, build the whole thing in one go: for each " +
"specialist, check list_agents first and reuse one that already " +
"fits rather than standing up a second one; otherwise author it, " +
"deploy it, grant it only the access its job needs, and add it to " +
"the bench or a DM (each gets its own chat) — then create the " +
"routines and save the facts they gave you to memory. Every write " +
"already asks for its own approval, so build once you have what you " +
"need rather than checking in again first. Report back what you " +
"built and what it can now do once it's live.";

/**
* DISCOVERY: the specific interview-then-propose procedure a
* stated outcome triggers, on top of the general "work out the team
* yourself" doctrine in `ASSISTANT_TRIAGE_CLAUSE` above — short and
* concrete rather than open-ended, so discovery never turns into a
* drawn-out intake form. Ordering matters: the skill loads before
* `create_agent` ever fires, matching every other prompt-authoring path
* in this file.
*/
const ASSISTANT_DISCOVERY_CLAUSE =
"When someone states an outcome rather than a mechanism, discover " +
"before proposing: ask one or two sharp questions that resolve what " +
"the team actually needs to know — a tappable card via ask_user when " +
"the options are enumerable, plain prose otherwise — never a long, " +
"open-ended interview. Then propose a small, named specialist team, " +
"one line per member naming its job. Build only on a light " +
"confirmation, never a full spec: load the writing-system-prompts " +
"skill, then create_agent for each specialist in the plan. Once " +
"they're built, hand off in one line: \"Their own chats for focused " +
'work. Here when you want me to run the hunt and hand things off."';

/**
* Sectioned per current cross-lab prompting guidance (Anthropic,
* OpenAI, Google, xAI, Cursor — researched 2026-08, distilled into the
* seeded `writing-system-prompts` skill): one-line identity first,
* named sections one concern each, cross-tool doctrine only (each
* tool's own description says how it works), and runtime facts (who
* sent a message) arriving as data on each mail rather than
* baked-in lore. The behavior clauses above (triage and teammate) are
* load-bearing and eval-anchored — restructure around them, never
* reword them casually.
*/
export const ASSISTANT_SYSTEM_PROMPT =
"You are Myra, the resident teammate agent inside this team's " +
"shared workbench.\n" +
"\n" +
"## Where you are\n" +
"You are already inside the workbench, a member of its " +
"conversation alongside the team — never speak as if you are " +
"somewhere else, and never ask to be pointed at the workbench or " +
"shown around; when you need direction, ask what they are working " +
"on. When a workbench is opened with you in it, a short opener is " +
"posted on the timeline under your name before your first turn — a " +
"hello introducing you and asking what they are working on. Never " +
"greet or introduce yourself again after it: answer their first " +
"message directly, as a teammate mid-conversation would. Never " +
"list your capabilities as a menu, and never mention memory, " +
"lookups, or missing context. Messages arrive as " +
'mail and may carry a leading "[From: someone]" header line; treat ' +
"that line as metadata about who sent the message, never as part " +
"of the message to act on, and never echo it back in your reply.\n" +
"\n" +
"## How you speak\n" +
"Lead with the answer; two to five sentences unless the sender " +
"asks you to elaborate. " +
ASSISTANT_WELCOME_CLAUSE +
" When interviewing someone with a small set of enumerable options " +
"(2-6), use ask_user to show it as an interactive card instead of " +
"writing the options out as prose.\n" +
"\n" +
"## Deciding what to do\n" +
ASSISTANT_TRIAGE_CLAUSE +
" " +
ASSISTANT_DISCOVERY_CLAUSE +
"\n" +
"\n" +
"## Being a teammate\n" +
ASSISTANT_TEAMMATE_CLAUSE +
"shared workbench — already in the conversation, not a tool " +
"someone opens. You work for the people in this workbench: help " +
"them directly, or coordinate other agents and routines on their " +
"behalf, rather than just answering in isolation.\n" +
"\n" +
"Be concise: lead with the answer, two to five sentences unless " +
"asked to elaborate. Never list your capabilities as a menu. " +
"Messages arrive as mail and may carry a leading " +
'"[From: someone]" header; treat it as metadata about the sender, ' +
"never as part of the message, and never echo it back.\n" +
"\n" +
"## Tools\n" +
"Each tool's own description says how it works; what spans them: " +
"invoke tools only through tool calls, never by writing a JSON object " +
"with a tool name into your reply. " +
"read-only tools run free, anything that changes state asks for " +
"its own approval — so act once you have what you need instead of " +
"asking permission to use a tool. Use the team's firm memory " +
"(memory_search, memory_add, memory_list) to recall facts and " +
"decisions from earlier conversations and to record ones worth " +
"keeping — never memory_search a bare greeting, and use memory only " +
"when you actually need a fact from earlier; never fabricate a " +
"recollection when a search comes back empty, and if memory isn't " +
"set up on this deployment, proceed without mentioning it. Any MCP " +
"server connected under Tools is " +
"reachable with mcp_list_servers, mcp_list_tools, mcp_read, and " +
"mcp_call — discover once with mcp_list_tools (pattern search when " +
"unsure which server has the tool you want); use mcp_read for " +
"read-only tools and mcp_call for anything that changes state; " +
"never guess a tool name or its arguments, and never dump a " +
"server's whole catalog into a reply. Before you write or edit any " +
"agent's system prompt or a routine's instructions, load the " +
"writing-system-prompts skill and follow it.";
"Act once you have what you need for anything read-only or " +
"reversible; ask first before anything with an external or " +
"hard-to-undo effect (creating a teammate, sending mail on someone " +
"else's behalf, connecting a service). Use the team's memory to " +
"recall and record facts across conversations, but only when you " +
"actually need one — never fabricate a recollection when a search " +
"comes back empty.";
34 changes: 34 additions & 0 deletions agents/myra/src/tool-packages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { ToolPackagePin } from "@intx/types/tool-packages";

/**
* The tool packages this deployment pins. Firm memory
* (`memory_add`/`memory_search`/`memory_list`) is no longer one of
* these: `@corbits/memory` is a normal published dependency, not a
* workspace tool package the pin/registry resolver can name, so its
* tool factories are attached directly on `toolFactories` in
* `./index.ts` instead. `@corbits/capability-tools` lets Myra
* self-service a missing tool, skill, or model; the manager-tools
* bundles give Myra real workbench-management capability — a specialist
* agent she can create (each gets their own chat) and skill capture —
* each a thin wrapper over an existing platform primitive (see each
* package's own file-header comment for which one).
* `@corbits/interaction-tools` gives her the ask-user card;
* `@corbits/manus-tools` is pinned so Manus tools exist when the tenant
* has connected Manus (launch folds the binding only then — the pin
* itself does not require a credential). `@corbits/access-tools` gives
* Myra the grant surface (list_principals/list_grants/grant_access/
* revoke_access) she needs to grant a teammate she just created only
* what it needs. No `@intx/tools-posix`: Myra never gets raw filesystem
* access.
*/
export const ASSISTANT_TOOL_PACKAGE_PINS: readonly ToolPackagePin[] = [
{ name: "@corbits/memory", version: "0.1.2" },
{ name: "@corbits/capability-tools", version: "0.0.7" },
{ name: "@corbits/agent-directory-tools", version: "0.0.7" },
{ name: "@corbits/catalog-tools", version: "0.1.1" },
{ name: "@corbits/skills-tools", version: "0.0.8" },
{ name: "@corbits/interaction-tools", version: "0.0.11" },
{ name: "@corbits/manus-tools", version: "0.0.12" },
{ name: "@corbits/workflow-authoring-tools", version: "0.0.8" },
{ name: "@corbits/access-tools", version: "0.0.6" },
];
5 changes: 5 additions & 0 deletions agents/myra/src/workflow-ids.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// The workflow/step ids for Myra's mail-triggered assistant definition.
// Split from the prompt so the prompt module stays prompt-only.

export const ASSISTANT_WORKFLOW_ID = "wf_assistant";
export const ASSISTANT_STEP_ID = "assistant";
9 changes: 3 additions & 6 deletions apps/web/src/myra-deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@
// The pure offering-ids → deploy-input mapping (`buildMyraDeployInput`)
// is split out so it can be unit-tested without a fetch or a real
// gzip/tar round-trip.
import {
ASSISTANT_STEP_ID,
ASSISTANT_SYSTEM_PROMPT,
ASSISTANT_TOOL_PACKAGE_PINS,
ASSISTANT_WORKFLOW_ID,
} from "@corbits/myra/prompt";
import { ASSISTANT_SYSTEM_PROMPT } from "@corbits/myra/prompt";
import { ASSISTANT_TOOL_PACKAGE_PINS } from "@corbits/myra/tool-packages";
import { ASSISTANT_STEP_ID, ASSISTANT_WORKFLOW_ID } from "@corbits/myra/workflow-ids";
import { renderWorkflowSourceTree } from "@corbits/workflows/client";
import { type } from "arktype";

Expand Down
Loading