pi-roundtable 0.33.0 → 0.35.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/CHANGELOG.md +19 -0
- package/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/docs/plugins.md +2 -2
- package/package.json +1 -2
- package/src/cli/checks/configuration.ts +2 -2
- package/src/cli/checks/database.ts +2 -2
- package/src/cli/checks/identity.ts +1 -1
- package/src/cli/checks/model.ts +1 -1
- package/src/cli/cli.ts +2 -2
- package/src/cli/principal.ts +1 -1
- package/src/cli/project.ts +2 -2
- package/src/cli/runtime.ts +3 -3
- package/src/cli/start.ts +1 -1
- package/src/core/agents/agent-claim.ts +4 -4
- package/src/core/agents/agent-dashboard.ts +3 -3
- package/src/core/agents/agent-messages.ts +2 -2
- package/src/core/agents/agent-outbox.ts +1 -1
- package/src/core/agents/agent-ports.ts +1 -1
- package/src/core/agents/agent-prompt.ts +4 -4
- package/src/core/agents/agent-rules.ts +1 -1
- package/src/core/agents/agent-schema.ts +4 -1
- package/src/core/agents/agent-settings.ts +2 -2
- package/src/core/agents/agent-store.ts +9 -9
- package/src/core/agents/agent-team-fixture.ts +4 -3
- package/src/core/agents/agent-team.ts +12 -16
- package/src/core/agents/agent-tools.ts +15 -15
- package/src/core/agents/avatar-refresh.ts +1 -1
- package/src/core/agents/avatar-studio.ts +2 -2
- package/src/core/agents/group-round.ts +2 -2
- package/src/core/agents/group-turns.ts +1 -1
- package/src/core/agents/helper-create.ts +24 -40
- package/src/core/agents/helper-modes.ts +2 -2
- package/src/core/agents/helper-preset-ops.ts +207 -0
- package/src/core/agents/helper-preset-tools.ts +109 -0
- package/src/core/agents/helper-presets.ts +128 -0
- package/src/core/agents/helper-test-kit.ts +1 -1
- package/src/core/agents/helper-tools.ts +42 -22
- package/src/core/agents/helper-work.ts +1 -1
- package/src/core/agents/message-target.ts +1 -1
- package/src/core/agents/routes.ts +1 -1
- package/src/core/agents/team-approval.ts +2 -2
- package/src/core/agents/team-editing.ts +2 -2
- package/src/core/agents/team-keys.ts +1 -1
- package/src/core/agents/team-layout.ts +1 -1
- package/src/core/agents/team-options.ts +4 -4
- package/src/core/agents/team-selection.ts +1 -1
- package/src/core/agents/team-status.ts +1 -1
- package/src/core/agents/team-text.ts +3 -3
- package/src/core/agents/team-turn-types.ts +7 -7
- package/src/core/agents/team-turns.ts +3 -3
- package/src/core/attachments/attachment-fetcher.ts +1 -1
- package/src/core/attachments/attachment-port.ts +2 -2
- package/src/core/attachments/attachment-retention.ts +3 -3
- package/src/core/attachments/attachment-store.ts +2 -2
- package/src/core/attachments/model-images.ts +1 -1
- package/src/core/attachments/turn-attachments.ts +1 -1
- package/src/core/builtin/agent-server.ts +17 -10
- package/src/core/builtin/channel-context.ts +2 -2
- package/src/core/builtin/discord-admin.ts +2 -2
- package/src/core/builtin/discord.ts +4 -3
- package/src/core/{identity/identity-plugin.ts → builtin/identity.ts} +15 -12
- package/src/core/builtin/modules.ts +12 -12
- package/src/core/builtin/prompts.ts +3 -3
- package/src/core/builtin/seeds.ts +1 -1
- package/src/core/builtin/session-tool.ts +1 -1
- package/src/core/builtin/skills.ts +3 -3
- package/src/core/builtin/stores.ts +10 -5
- package/src/core/builtin/threads.ts +2 -2
- package/src/core/builtin/worker-sessions.ts +3 -3
- package/src/core/config/access.ts +3 -3
- package/src/core/config/adapters.ts +1 -1
- package/src/core/config/config-schema.ts +9 -3
- package/src/core/config/config.ts +9 -10
- package/src/core/config/ops.ts +1 -1
- package/src/core/config/peer-bots.ts +74 -0
- package/src/core/config/routing.ts +1 -1
- package/src/core/contract/attachments.ts +1 -1
- package/src/core/contract/channels.ts +3 -5
- package/src/core/contract/runtime.ts +6 -6
- package/src/core/contract/surface.ts +3 -3
- package/src/core/conversations/conversation-registry.ts +1 -1
- package/src/core/conversations/conversation-retention.ts +2 -2
- package/src/core/conversations/conversation-store.ts +1 -1
- package/src/core/conversations/conversations-plugin.ts +2 -2
- package/src/core/db/migrations.ts +2 -2
- package/src/core/discord/agent-commands.ts +2 -2
- package/src/core/discord/agent-discord.ts +1 -1
- package/src/core/discord/agent-panel.ts +1 -1
- package/src/core/discord/card-audience.ts +1 -1
- package/src/core/discord/card-copies.ts +1 -1
- package/src/core/discord/channel-context.ts +1 -1
- package/src/core/discord/channel-executor.ts +1 -1
- package/src/core/discord/channel-operations.ts +1 -1
- package/src/core/discord/command-collection.ts +1 -1
- package/src/core/discord/compose-commands.ts +1 -1
- package/src/core/discord/context-images.ts +1 -1
- package/src/core/discord/discord-owners.ts +2 -2
- package/src/core/discord/discord-surface.ts +2 -2
- package/src/core/discord/member-events.ts +2 -2
- package/src/core/discord/message-changes.ts +1 -1
- package/src/core/discord/owner-cards.ts +1 -1
- package/src/core/discord/owner-command.ts +1 -1
- package/src/core/discord/schedule-commands.ts +1 -1
- package/src/core/domain/conversation.ts +5 -3
- package/src/core/{models.ts → domain/models.ts} +1 -1
- package/src/core/domain/ports.ts +2 -2
- package/src/core/{sessions.ts → domain/sessions.ts} +6 -6
- package/src/core/{define-roundtable.ts → host/define-roundtable.ts} +29 -29
- package/src/core/{drain.ts → host/drain.ts} +2 -7
- package/src/core/{events.ts → host/events.ts} +2 -2
- package/src/core/{host-background.ts → host/host-background.ts} +3 -3
- package/src/core/{host-registration.ts → host/host-registration.ts} +30 -30
- package/src/core/{host.ts → host/host.ts} +19 -15
- package/src/core/http/listeners.ts +2 -2
- package/src/core/http/websocket.ts +1 -1
- package/src/core/identity/access-policy.ts +8 -8
- package/src/core/identity/actor-facts.ts +1 -1
- package/src/core/identity/caching-principal-store.ts +1 -1
- package/src/core/identity/config-owner.ts +1 -1
- package/src/core/identity/contact.ts +2 -2
- package/src/core/identity/identity-links.ts +2 -2
- package/src/core/identity/identity-port.ts +2 -2
- package/src/core/identity/identity-schema.ts +1 -1
- package/src/core/identity/identity-service.ts +3 -3
- package/src/core/identity/identity-view.ts +1 -1
- package/src/core/{identity.ts → identity/owner-identity.ts} +1 -1
- package/src/core/identity/person-profiles.ts +1 -1
- package/src/core/identity/plugin-identities.ts +2 -2
- package/src/core/identity/principal-reads.ts +1 -1
- package/src/core/identity/principal-store.ts +1 -1
- package/src/core/identity/principal-types.ts +1 -1
- package/src/core/identity/seen-throttle.ts +1 -1
- package/src/core/{speakers.ts → identity/speakers.ts} +3 -6
- package/src/core/images/codex-images-plugin.ts +3 -3
- package/src/core/interactions/prompts.ts +1 -1
- package/src/core/judging/confirmation-judge.ts +1 -1
- package/src/core/judging/effort-judge.ts +2 -2
- package/src/core/judging/model-judge.ts +1 -1
- package/src/core/modes/conversation-modes.ts +4 -4
- package/src/core/modes/mode-inheritance.ts +1 -1
- package/src/core/modes/modes-plugin.ts +2 -2
- package/src/core/modules/background/background-turns.ts +4 -4
- package/src/core/modules/delegation/delegate.ts +3 -3
- package/src/core/modules/delegation/delegator.ts +4 -4
- package/src/core/modules/delegation/web-research-worker.ts +2 -2
- package/src/core/modules/delegation/worker-session.ts +5 -2
- package/src/core/modules/discord-admin/discord-admin.ts +1 -1
- package/src/core/modules/host-shell/shell-policy.ts +1 -1
- package/src/core/modules/memory/owner-memory-store.ts +1 -1
- package/src/core/modules/memory/owner-memory.ts +6 -3
- package/src/core/modules/notify/notify.ts +4 -1
- package/src/core/modules/notify/session-notify.ts +3 -3
- package/src/core/modules/prompts/prompt-documents.ts +1 -1
- package/src/core/modules/schedules/precheck-tools.ts +4 -4
- package/src/core/modules/schedules/prechecks.ts +2 -2
- package/src/core/modules/schedules/recurrence.ts +6 -1
- package/src/core/modules/schedules/schedule-prechecks.ts +4 -4
- package/src/core/modules/schedules/schedule-store.ts +2 -2
- package/src/core/modules/schedules/schedule-tools.ts +4 -4
- package/src/core/modules/schedules/scheduled-turn-text.ts +1 -1
- package/src/core/modules/schedules/scheduler.ts +3 -3
- package/src/core/modules/schedules/schedules.ts +5 -5
- package/src/core/modules/skills/missing-warning.ts +1 -1
- package/src/core/modules/skills/package-skills.ts +1 -1
- package/src/core/modules/skills/skill-registry.ts +2 -2
- package/src/core/modules/skills/skill-rules.ts +1 -1
- package/src/core/modules/skills/skill-tools.ts +1 -1
- package/src/core/ops/error-reporter.ts +2 -2
- package/src/core/ops/ops-alerts.ts +1 -1
- package/src/core/{define.ts → plugin-api/define.ts} +18 -20
- package/src/core/{event-types.ts → plugin-api/event-types.ts} +1 -1
- package/src/core/{holds.ts → plugin-api/holds.ts} +3 -3
- package/src/core/{plugin-removed.ts → plugin-api/plugin-removed.ts} +2 -2
- package/src/core/{plugin.ts → plugin-api/plugin.ts} +26 -26
- package/src/core/{services.ts → plugin-api/services.ts} +28 -28
- package/src/core/{tool-turn.ts → plugin-api/tool-turn.ts} +12 -5
- package/src/core/presence/delivery-router.ts +1 -1
- package/src/core/presence/direct-channels.ts +1 -1
- package/src/core/registry/chat-commands.ts +1 -1
- package/src/core/registry/contributions.ts +11 -11
- package/src/core/registry/providers.ts +2 -2
- package/src/core/registry/services.ts +2 -2
- package/src/core/registry/surface-service.ts +1 -1
- package/src/core/routing/actor-of.ts +1 -1
- package/src/core/routing/channel-queue.ts +2 -2
- package/src/core/routing/channel-router.ts +3 -3
- package/src/core/routing/claim-events.ts +2 -2
- package/src/core/routing/conversation-turns.ts +10 -6
- package/src/core/routing/forward-join.ts +1 -1
- package/src/core/routing/message-observers.ts +1 -1
- package/src/core/routing/message-text.ts +1 -1
- package/src/core/routing/peer-bots.ts +6 -74
- package/src/core/routing/queued-messages.ts +2 -2
- package/src/core/routing/settle-turn.ts +1 -1
- package/src/core/routing/surface-port.ts +3 -3
- package/src/core/runtime/ask-questions.ts +1 -1
- package/src/core/runtime/bridge-guard.ts +5 -5
- package/src/core/runtime/chat-only.ts +1 -1
- package/src/core/runtime/conversation-sessions.ts +2 -2
- package/src/core/runtime/extensions/agent-prompt.ts +1 -1
- package/src/core/runtime/extensions/ask-user-text.ts +5 -1
- package/src/core/runtime/extensions/ask-user.ts +4 -1
- package/src/core/runtime/extensions/card-ask.ts +1 -1
- package/src/core/runtime/extensions/confirmation-fixture.ts +1 -1
- package/src/core/runtime/extensions/confirmation-gate-extension.ts +1 -1
- package/src/core/runtime/extensions/confirmation-gate.ts +5 -5
- package/src/core/runtime/extensions/gate-refusals.ts +5 -2
- package/src/core/runtime/extensions/held-calls.ts +2 -2
- package/src/core/runtime/extensions/hold-describer.ts +3 -3
- package/src/core/runtime/extensions/hold-lookups.ts +4 -4
- package/src/core/runtime/extensions/persona-prompt.ts +1 -1
- package/src/core/runtime/extensions/prompt-read.ts +1 -1
- package/src/core/runtime/extensions/yolo.ts +1 -1
- package/src/core/runtime/interim-text.ts +1 -1
- package/src/core/runtime/pi-agent-runtime.ts +4 -4
- package/src/core/runtime/running-turn.ts +1 -1
- package/src/core/runtime/runtime-plugin.ts +13 -8
- package/src/core/runtime/runtime-types.ts +14 -10
- package/src/core/runtime/session-conversation.ts +3 -3
- package/src/core/runtime/session-factory.ts +5 -5
- package/src/core/runtime/thinking-level.ts +2 -2
- package/src/core/{tool-tiers.ts → runtime/tool-tiers.ts} +5 -5
- package/src/core/runtime/turn-answer.ts +1 -1
- package/src/core/runtime/turn-budget.ts +1 -1
- package/src/core/runtime/turn-limits.ts +1 -1
- package/src/core/runtime/turn-tools.ts +2 -2
- package/src/core/runtime/worker-task.ts +1 -1
- package/src/core/shared/attach-file-tool.ts +1 -1
- package/src/core/shared/child-env.ts +3 -5
- package/src/core/shared/delegate-tool.ts +1 -1
- package/src/core/shared/generate-image-tool.ts +1 -1
- package/src/core/{modules/background → shared}/personal-target.ts +2 -2
- package/src/core/{reply-files.ts → shared/reply-files.ts} +1 -1
- package/src/core/testing/eager-catalog.ts +1 -1
- package/src/core/testing/locale.ts +1 -1
- package/src/core/testing/map-identity.ts +5 -1
- package/src/core/testing/module-sessions.ts +3 -3
- package/src/core/testing/modules.ts +17 -13
- package/src/core/testing/owner.ts +2 -2
- package/src/core/testing/recording-logger.ts +1 -1
- package/src/core/testing/run-tool.ts +2 -2
- package/src/core/testing/surface-contract-support.ts +1 -1
- package/src/core/testing/surface-contract.ts +2 -2
- package/src/core/testing/test-host.ts +12 -12
- package/src/core/testing/thread-host.ts +1 -1
- package/src/core/testing/tool-set.ts +3 -3
- package/src/core/threads/dispatch-threads.ts +1 -1
- package/src/core/tool-set.snapshot.json +12 -0
- package/src/index.ts +76 -72
- package/src/kit/domain.ts +9 -9
- package/src/kit/holds.ts +4 -1
- package/src/kit/jev-judge.ts +1 -1
- package/src/kit/jev.ts +1 -1
- package/src/kit/presentation.ts +1 -1
- package/src/kit/support.ts +3 -3
- package/src/testing.ts +21 -20
- /package/src/core/{errors.ts → kernel/errors.ts} +0 -0
- /package/src/core/{freeze.ts → kernel/freeze.ts} +0 -0
- /package/src/core/{log.ts → kernel/log.ts} +0 -0
- /package/src/core/{time.ts → kernel/time.ts} +0 -0
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { CharacterInput } from "../../characters/index.ts";
|
|
2
|
-
import { helpersOf } from "../config/helpers.ts";
|
|
3
2
|
import { AgentError } from "../domain/errors.ts";
|
|
4
3
|
import type { AgentTurnScope } from "../domain/ports.ts";
|
|
5
|
-
import type { Speaker } from "../speakers.ts";
|
|
6
|
-
import { toolTiers } from "../tool-tiers.ts";
|
|
4
|
+
import type { Speaker } from "../identity/speakers.ts";
|
|
7
5
|
import { isHelper } from "./agent-rules.ts";
|
|
8
6
|
import type { Agent } from "./agent-store.ts";
|
|
9
7
|
import { followOrigin } from "./helper-modes.ts";
|
|
8
|
+
import {
|
|
9
|
+
checkHelperGrant,
|
|
10
|
+
type HelperFields,
|
|
11
|
+
helperMaker,
|
|
12
|
+
withPreset,
|
|
13
|
+
} from "./helper-preset-ops.ts";
|
|
10
14
|
import type { TeamContext } from "./team-options.ts";
|
|
11
15
|
|
|
12
16
|
/** The team's way of making an agent, which `createHelper` uses to make a temp knight. */
|
|
@@ -40,46 +44,26 @@ export async function createHelper(
|
|
|
40
44
|
ctx: TeamContext,
|
|
41
45
|
make: MakeAgent,
|
|
42
46
|
caller: AgentTurnScope,
|
|
43
|
-
input: {
|
|
44
|
-
name?: string;
|
|
45
|
-
displayName: string;
|
|
46
|
-
prompt: string;
|
|
47
|
-
task: string;
|
|
48
|
-
character?: CharacterInput;
|
|
49
|
-
skills?: string[];
|
|
50
|
-
model?: string;
|
|
51
|
-
thinking?: string;
|
|
52
|
-
},
|
|
47
|
+
input: HelperFields & { name?: string; task: string },
|
|
53
48
|
): Promise<string> {
|
|
54
49
|
const { store, logger } = ctx.options;
|
|
55
|
-
const limits =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
50
|
+
const { speaker, parent, limits } = helperMaker(ctx, caller, "helper_create");
|
|
51
|
+
// A preset saved earlier is checked again now, merged with the call.
|
|
52
|
+
const merged = await withPreset(ctx, parent, input);
|
|
53
|
+
const {
|
|
54
|
+
task,
|
|
55
|
+
name: given,
|
|
56
|
+
model,
|
|
57
|
+
thinking,
|
|
58
|
+
preset: _preset,
|
|
59
|
+
...rest
|
|
60
|
+
} = merged;
|
|
61
|
+
const { displayName, prompt } = rest;
|
|
62
|
+
if (!displayName || !prompt)
|
|
60
63
|
throw new AgentError(
|
|
61
|
-
"
|
|
64
|
+
"Give display_name and prompt, or a preset (from helper_preset_list) that has them.",
|
|
62
65
|
);
|
|
63
|
-
|
|
64
|
-
if (isHelper(parent))
|
|
65
|
-
throw new AgentError(
|
|
66
|
-
`You are a temp knight of "${parent.parent}" and cannot make temp knights; ask it to.`,
|
|
67
|
-
);
|
|
68
|
-
const { task, name: given, model, thinking, ...rest } = input;
|
|
69
|
-
// A temp knight never gets more than its parent unless the speaker could grant it by hand.
|
|
70
|
-
const tiers = ctx.options.toolTiers ?? toolTiers();
|
|
71
|
-
if (!tiers.allows(speaker.tier, "agent_update") && (model || thinking))
|
|
72
|
-
throw new AgentError(
|
|
73
|
-
"A temp knight runs your model and thinking level; choosing others needs a higher tier.",
|
|
74
|
-
);
|
|
75
|
-
if (rest.skills?.length && !tiers.allows(speaker.tier, "agent_skills")) {
|
|
76
|
-
const own = new Set(ctx.options.skills?.carriedNames(parent.name) ?? []);
|
|
77
|
-
const extra = rest.skills.filter((skill) => !own.has(skill));
|
|
78
|
-
if (extra.length > 0)
|
|
79
|
-
throw new AgentError(
|
|
80
|
-
`A temp knight can carry only skills you carry; not allowed: ${extra.join(", ")}.`,
|
|
81
|
-
);
|
|
82
|
-
}
|
|
66
|
+
checkHelperGrant(ctx, speaker, parent, merged);
|
|
83
67
|
const name = given ?? nextName(ctx, parent.name);
|
|
84
68
|
// Everything that can be refused is checked before anything is made or archived.
|
|
85
69
|
store.checkNewName(name);
|
|
@@ -92,7 +76,7 @@ export async function createHelper(
|
|
|
92
76
|
parent,
|
|
93
77
|
origin: ctx.turns.turnChannel(caller),
|
|
94
78
|
},
|
|
95
|
-
{ ...rest, name },
|
|
79
|
+
{ ...rest, displayName, prompt, name },
|
|
96
80
|
{ model, thinking },
|
|
97
81
|
);
|
|
98
82
|
const helper = made.agent;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AgentTurnScope } from "../domain/ports.ts";
|
|
2
2
|
import { SYSTEM_PRINCIPAL } from "../identity/principal-store.ts";
|
|
3
|
+
import type { Speaker } from "../identity/speakers.ts";
|
|
3
4
|
import type { ModeOrigins } from "../modes/mode-inheritance.ts";
|
|
4
|
-
import type { AgentDirectory } from "../services.ts";
|
|
5
|
-
import type { Speaker } from "../speakers.ts";
|
|
5
|
+
import type { AgentDirectory } from "../plugin-api/services.ts";
|
|
6
6
|
import { isHelper } from "./agent-rules.ts";
|
|
7
7
|
import type { Agent } from "./agent-store.ts";
|
|
8
8
|
import { agentOfChannel, groupOfChannel, keysOf } from "./team-keys.ts";
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import type { CharacterInput } from "../../characters/index.ts";
|
|
2
|
+
import { helpersOf, type ResolvedHelpers } from "../config/helpers.ts";
|
|
3
|
+
import { AgentError } from "../domain/errors.ts";
|
|
4
|
+
import { THINKING_LEVELS } from "../domain/models.ts";
|
|
5
|
+
import type { AgentTurnScope } from "../domain/ports.ts";
|
|
6
|
+
import type { Speaker } from "../identity/speakers.ts";
|
|
7
|
+
import { toolTiers } from "../runtime/tool-tiers.ts";
|
|
8
|
+
import {
|
|
9
|
+
type Agent,
|
|
10
|
+
checkDisplayName,
|
|
11
|
+
checkModelRef,
|
|
12
|
+
checkPrompt,
|
|
13
|
+
isHelper,
|
|
14
|
+
} from "./agent-rules.ts";
|
|
15
|
+
import type { HelperPreset } from "./helper-presets.ts";
|
|
16
|
+
import type { TeamContext } from "./team-options.ts";
|
|
17
|
+
|
|
18
|
+
/** What the helper_preset tools ask of the team. */
|
|
19
|
+
export type PresetAction =
|
|
20
|
+
| { kind: "set"; preset: HelperPreset }
|
|
21
|
+
| { kind: "list"; name?: string }
|
|
22
|
+
| { kind: "delete"; name: string };
|
|
23
|
+
|
|
24
|
+
/** What a temp knight is made with; a preset fills in what the call leaves out. */
|
|
25
|
+
export interface HelperFields {
|
|
26
|
+
preset?: string;
|
|
27
|
+
displayName?: string;
|
|
28
|
+
prompt?: string;
|
|
29
|
+
character?: CharacterInput;
|
|
30
|
+
skills?: string[];
|
|
31
|
+
model?: string;
|
|
32
|
+
thinking?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const PRESET_NAME = /^[a-z0-9-]{1,32}$/;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The speaker of the caller's turn and the knight it is, refused when temp knights are off, outside
|
|
39
|
+
* an agent turn, or for a temp knight, which cannot make temp knights.
|
|
40
|
+
*/
|
|
41
|
+
export function helperMaker(
|
|
42
|
+
ctx: TeamContext,
|
|
43
|
+
caller: AgentTurnScope,
|
|
44
|
+
tool: string,
|
|
45
|
+
): { speaker: Speaker; parent: Agent; limits: ResolvedHelpers } {
|
|
46
|
+
const limits = helpersOf(ctx.options.helpers);
|
|
47
|
+
if (!limits)
|
|
48
|
+
throw new AgentError("Temp knights are switched off on this host.");
|
|
49
|
+
const speaker = ctx.turns.speakerOf(caller);
|
|
50
|
+
if (!speaker)
|
|
51
|
+
throw new AgentError(`${tool} can only be used during an agent turn.`);
|
|
52
|
+
const parent = ctx.options.store.activeAgent(caller.name);
|
|
53
|
+
if (isHelper(parent))
|
|
54
|
+
throw new AgentError(
|
|
55
|
+
`You are a temp knight of "${parent.parent}" and cannot make temp knights; ask it to.`,
|
|
56
|
+
);
|
|
57
|
+
return { speaker, parent, limits };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A temp knight never gets more than its parent unless the speaker could grant it by hand: another
|
|
62
|
+
* model or thinking level needs the agent_update tier, a skill the parent does not carry the
|
|
63
|
+
* agent_skills tier.
|
|
64
|
+
*/
|
|
65
|
+
export function checkHelperGrant(
|
|
66
|
+
ctx: TeamContext,
|
|
67
|
+
speaker: Speaker,
|
|
68
|
+
parent: Agent,
|
|
69
|
+
fields: Pick<HelperFields, "model" | "thinking" | "skills">,
|
|
70
|
+
): void {
|
|
71
|
+
const tiers = ctx.options.toolTiers ?? toolTiers();
|
|
72
|
+
if (
|
|
73
|
+
!tiers.allows(speaker.tier, "agent_update") &&
|
|
74
|
+
(fields.model || fields.thinking)
|
|
75
|
+
)
|
|
76
|
+
throw new AgentError(
|
|
77
|
+
"A temp knight runs your model and thinking level; choosing others needs a higher tier.",
|
|
78
|
+
);
|
|
79
|
+
if (fields.skills?.length && !tiers.allows(speaker.tier, "agent_skills")) {
|
|
80
|
+
const own = new Set(ctx.options.skills?.carriedNames(parent.name) ?? []);
|
|
81
|
+
const extra = fields.skills.filter((skill) => !own.has(skill));
|
|
82
|
+
if (extra.length > 0)
|
|
83
|
+
throw new AgentError(
|
|
84
|
+
`A temp knight can carry only skills you carry; not allowed: ${extra.join(", ")}.`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The call's fields over the named preset: what the call gives replaces the preset's, and its
|
|
91
|
+
* skills are added after the preset's. An unknown preset is refused with the caller's names.
|
|
92
|
+
*/
|
|
93
|
+
export async function withPreset<T extends HelperFields>(
|
|
94
|
+
ctx: TeamContext,
|
|
95
|
+
parent: Agent,
|
|
96
|
+
input: T,
|
|
97
|
+
): Promise<T> {
|
|
98
|
+
const { preset: name, ...given } = input;
|
|
99
|
+
if (!name) return input;
|
|
100
|
+
const presets = ctx.options.store.presets;
|
|
101
|
+
const preset = await presets.get(parent.name, name);
|
|
102
|
+
if (!preset) {
|
|
103
|
+
const names = (await presets.list(parent.name)).map((p) => p.name);
|
|
104
|
+
throw new AgentError(
|
|
105
|
+
names.length > 0
|
|
106
|
+
? `You have no preset "${name}". Your presets: ${names.join(", ")}.`
|
|
107
|
+
: `You have no preset "${name}", nor any other; save one with helper_preset_set.`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
const skills = [...new Set([...preset.skills, ...(given.skills ?? [])])];
|
|
111
|
+
const character = { ...preset.character, ...given.character };
|
|
112
|
+
return {
|
|
113
|
+
...given,
|
|
114
|
+
displayName: given.displayName ?? preset.displayName,
|
|
115
|
+
prompt: given.prompt ?? preset.prompt,
|
|
116
|
+
...(Object.keys(character).length > 0 ? { character } : {}),
|
|
117
|
+
...(skills.length > 0 ? { skills } : {}),
|
|
118
|
+
...((given.model ?? preset.model)
|
|
119
|
+
? { model: given.model ?? preset.model }
|
|
120
|
+
: {}),
|
|
121
|
+
...((given.thinking ?? preset.thinking)
|
|
122
|
+
? { thinking: given.thinking ?? preset.thinking }
|
|
123
|
+
: {}),
|
|
124
|
+
} as T;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The helper_preset tools: an agent saves, lists, and deletes its own temp-knight presets. */
|
|
128
|
+
export async function presetAction(
|
|
129
|
+
ctx: TeamContext,
|
|
130
|
+
caller: AgentTurnScope,
|
|
131
|
+
action: PresetAction,
|
|
132
|
+
): Promise<string> {
|
|
133
|
+
const tool = `helper_preset_${action.kind}`;
|
|
134
|
+
const { speaker, parent } = helperMaker(ctx, caller, tool);
|
|
135
|
+
const presets = ctx.options.store.presets;
|
|
136
|
+
if (action.kind === "set") {
|
|
137
|
+
const { preset } = action;
|
|
138
|
+
checkPreset(ctx, preset);
|
|
139
|
+
checkHelperGrant(ctx, speaker, parent, preset);
|
|
140
|
+
const done = await presets.set(parent.name, preset);
|
|
141
|
+
return `${done === "created" ? "Created" : "Replaced"} the preset "${preset.name}"; make its temp knight with helper_create and preset "${preset.name}".`;
|
|
142
|
+
}
|
|
143
|
+
if (action.kind === "delete") {
|
|
144
|
+
if (!(await presets.delete(parent.name, action.name)))
|
|
145
|
+
throw new AgentError(`You have no preset "${action.name}".`);
|
|
146
|
+
return `Deleted the preset "${action.name}".`;
|
|
147
|
+
}
|
|
148
|
+
if (action.name) {
|
|
149
|
+
const preset = await presets.get(parent.name, action.name);
|
|
150
|
+
if (!preset) throw new AgentError(`You have no preset "${action.name}".`);
|
|
151
|
+
return presetText(preset);
|
|
152
|
+
}
|
|
153
|
+
const all = await presets.list(parent.name);
|
|
154
|
+
if (all.length === 0)
|
|
155
|
+
return "You have no presets; save one with helper_preset_set.";
|
|
156
|
+
return all.map(presetLine).join("\n");
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** The checks a temp knight's fields get when it is made, applied when the preset is saved. */
|
|
160
|
+
function checkPreset(ctx: TeamContext, preset: HelperPreset): void {
|
|
161
|
+
if (!PRESET_NAME.test(preset.name))
|
|
162
|
+
throw new AgentError(
|
|
163
|
+
`"${preset.name}" is not a preset name: use 1 to 32 lowercase letters, digits, and dashes.`,
|
|
164
|
+
);
|
|
165
|
+
checkDisplayName(preset.displayName);
|
|
166
|
+
checkPrompt(preset.prompt);
|
|
167
|
+
if (preset.model) checkModelRef(preset.model);
|
|
168
|
+
if (
|
|
169
|
+
preset.thinking &&
|
|
170
|
+
![...THINKING_LEVELS, "default"].includes(preset.thinking as never)
|
|
171
|
+
)
|
|
172
|
+
throw new AgentError(
|
|
173
|
+
`"${preset.thinking}" is not a thinking level; use one of ${THINKING_LEVELS.join(", ")}, or default.`,
|
|
174
|
+
);
|
|
175
|
+
if (preset.skills.length > 0) {
|
|
176
|
+
const registry = ctx.options.skills;
|
|
177
|
+
if (!registry)
|
|
178
|
+
throw new AgentError(
|
|
179
|
+
"Skills are off on this host, so a preset cannot carry any. Save it without skills.",
|
|
180
|
+
);
|
|
181
|
+
registry.checkRegistered(preset.skills);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const presetLine = (preset: HelperPreset): string => {
|
|
186
|
+
const prompt = preset.prompt.replace(/\s+/g, " ").trim();
|
|
187
|
+
const head = prompt.length > 80 ? `${prompt.slice(0, 80)}…` : prompt;
|
|
188
|
+
const extras = [
|
|
189
|
+
preset.skills.length > 0 ? `skills: ${preset.skills.join(", ")}` : "",
|
|
190
|
+
preset.model ? `model: ${preset.model}` : "",
|
|
191
|
+
].filter(Boolean);
|
|
192
|
+
return `${preset.name}: "${preset.displayName}"${extras.length > 0 ? ` (${extras.join("; ")})` : ""}: ${head}`;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const presetText = (preset: HelperPreset): string =>
|
|
196
|
+
[
|
|
197
|
+
`Preset "${preset.name}"`,
|
|
198
|
+
`Display name: ${preset.displayName}`,
|
|
199
|
+
`Skills: ${preset.skills.length > 0 ? preset.skills.join(", ") : "none"}`,
|
|
200
|
+
...(preset.character?.class ? [`Class: ${preset.character.class}`] : []),
|
|
201
|
+
...(preset.character?.palette
|
|
202
|
+
? [`Color: ${preset.character.palette}`]
|
|
203
|
+
: []),
|
|
204
|
+
...(preset.model ? [`Model: ${preset.model}`] : []),
|
|
205
|
+
...(preset.thinking ? [`Thinking: ${preset.thinking}`] : []),
|
|
206
|
+
`Prompt:\n${preset.prompt}`,
|
|
207
|
+
].join("\n");
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { THINKING_LEVELS } from "../domain/models.ts";
|
|
3
|
+
import type { AgentTurnScope } from "../domain/ports.ts";
|
|
4
|
+
import {
|
|
5
|
+
optionalString,
|
|
6
|
+
requiredString,
|
|
7
|
+
stringList,
|
|
8
|
+
type TextToolDef,
|
|
9
|
+
} from "../runtime/text-tools.ts";
|
|
10
|
+
import { CLASS, COLOR, DISPLAY, lookOf, PROMPT } from "./agent-tool-schema.ts";
|
|
11
|
+
import type { AgentOps } from "./agent-tools.ts";
|
|
12
|
+
|
|
13
|
+
export const MODEL = Type.String({
|
|
14
|
+
description:
|
|
15
|
+
"The model to run on, as <provider>/<model>; left out, yours. An unusable one is refused with the usable list.",
|
|
16
|
+
});
|
|
17
|
+
export const THINKING = Type.Union(
|
|
18
|
+
[...THINKING_LEVELS, "default"].map((level) => Type.Literal(level)),
|
|
19
|
+
{ description: "Its thinking level; left out, yours." },
|
|
20
|
+
);
|
|
21
|
+
const PRESET_NAME = Type.String({
|
|
22
|
+
pattern: "^[a-z0-9-]{1,32}$",
|
|
23
|
+
description: "The preset's name: lowercase letters, digits, and dashes.",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/** The tools that keep a knight's temp-knight presets, which only it sees and uses. */
|
|
27
|
+
export function helperPresetToolDefs(
|
|
28
|
+
ops: Pick<AgentOps, "helperPreset">,
|
|
29
|
+
scope: AgentTurnScope,
|
|
30
|
+
skillsOn: boolean,
|
|
31
|
+
): TextToolDef<
|
|
32
|
+
"helper_preset_set" | "helper_preset_list" | "helper_preset_delete"
|
|
33
|
+
>[] {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
name: "helper_preset_set",
|
|
37
|
+
label: "Save temp knight preset",
|
|
38
|
+
description:
|
|
39
|
+
"Save a temp knight you make often (its role prompt, skills, and look) as a preset, then make it with helper_create and preset instead of writing them again. Saving under a name you have replaces that preset whole. Only you see and use your presets; you may keep 20.",
|
|
40
|
+
parameters: Type.Object({
|
|
41
|
+
name: PRESET_NAME,
|
|
42
|
+
display_name: DISPLAY,
|
|
43
|
+
prompt: PROMPT,
|
|
44
|
+
class: Type.Optional(CLASS),
|
|
45
|
+
color: Type.Optional(COLOR),
|
|
46
|
+
model: Type.Optional(MODEL),
|
|
47
|
+
thinking: Type.Optional(THINKING),
|
|
48
|
+
...(skillsOn
|
|
49
|
+
? {
|
|
50
|
+
skills: Type.Optional(
|
|
51
|
+
Type.Array(Type.String(), {
|
|
52
|
+
description:
|
|
53
|
+
"Skills its temp knight carries, from skill_list.",
|
|
54
|
+
}),
|
|
55
|
+
),
|
|
56
|
+
}
|
|
57
|
+
: {}),
|
|
58
|
+
}),
|
|
59
|
+
run: (i) => {
|
|
60
|
+
const look = lookOf(i);
|
|
61
|
+
const model = optionalString(i, "model");
|
|
62
|
+
const thinking = optionalString(i, "thinking");
|
|
63
|
+
return ops.helperPreset(scope, {
|
|
64
|
+
kind: "set",
|
|
65
|
+
preset: {
|
|
66
|
+
name: requiredString(i, "name"),
|
|
67
|
+
displayName: requiredString(i, "display_name"),
|
|
68
|
+
prompt: requiredString(i, "prompt"),
|
|
69
|
+
skills: [...new Set(stringList(i, "skills") ?? [])],
|
|
70
|
+
...(Object.keys(look).length > 0 ? { character: look } : {}),
|
|
71
|
+
...(model ? { model } : {}),
|
|
72
|
+
...(thinking ? { thinking } : {}),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "helper_preset_list",
|
|
79
|
+
label: "List temp knight presets",
|
|
80
|
+
description:
|
|
81
|
+
"List your temp knight presets, one line each; with a name, show that preset in full.",
|
|
82
|
+
parameters: Type.Object({
|
|
83
|
+
name: Type.Optional(
|
|
84
|
+
Type.String({ description: "A preset to show in full." }),
|
|
85
|
+
),
|
|
86
|
+
}),
|
|
87
|
+
run: (i) => {
|
|
88
|
+
const name = optionalString(i, "name");
|
|
89
|
+
return ops.helperPreset(scope, {
|
|
90
|
+
kind: "list",
|
|
91
|
+
...(name ? { name } : {}),
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "helper_preset_delete",
|
|
97
|
+
label: "Delete temp knight preset",
|
|
98
|
+
description: "Delete one of your temp knight presets.",
|
|
99
|
+
parameters: Type.Object({
|
|
100
|
+
name: Type.String({ description: "The preset's name." }),
|
|
101
|
+
}),
|
|
102
|
+
run: (i) =>
|
|
103
|
+
ops.helperPreset(scope, {
|
|
104
|
+
kind: "delete",
|
|
105
|
+
name: requiredString(i, "name"),
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { SQL } from "bun";
|
|
2
|
+
import type { CharacterInput } from "../../characters/index.ts";
|
|
3
|
+
import { AgentError } from "../domain/errors.ts";
|
|
4
|
+
|
|
5
|
+
/** The most presets one agent may keep. */
|
|
6
|
+
export const MAX_HELPER_PRESETS = 20;
|
|
7
|
+
|
|
8
|
+
/** A temp knight an agent makes often: what `helper_create` takes, saved under a name. */
|
|
9
|
+
export interface HelperPreset {
|
|
10
|
+
name: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
prompt: string;
|
|
13
|
+
skills: string[];
|
|
14
|
+
character?: CharacterInput;
|
|
15
|
+
model?: string;
|
|
16
|
+
thinking?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface Row {
|
|
20
|
+
name: string;
|
|
21
|
+
display_name: string;
|
|
22
|
+
prompt: string;
|
|
23
|
+
skills: string[] | null;
|
|
24
|
+
character: CharacterInput | null;
|
|
25
|
+
model: string | null;
|
|
26
|
+
thinking: string | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const toPreset = (row: Row): HelperPreset => ({
|
|
30
|
+
name: row.name,
|
|
31
|
+
displayName: row.display_name,
|
|
32
|
+
prompt: row.prompt,
|
|
33
|
+
skills: row.skills ?? [],
|
|
34
|
+
...(row.character ? { character: row.character } : {}),
|
|
35
|
+
...(row.model ? { model: row.model } : {}),
|
|
36
|
+
...(row.thinking ? { thinking: row.thinking } : {}),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The temp-knight presets, each owned by the agent that saved it; only that agent reads or uses
|
|
41
|
+
* them. They outlive an archive, so an agent restored finds its presets.
|
|
42
|
+
*/
|
|
43
|
+
export class HelperPresets {
|
|
44
|
+
readonly #sql: SQL;
|
|
45
|
+
readonly #guild: string;
|
|
46
|
+
|
|
47
|
+
constructor(sql: SQL, guildId: string) {
|
|
48
|
+
this.#sql = sql;
|
|
49
|
+
this.#guild = guildId;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The table, created by the agents' migrations. */
|
|
53
|
+
static readonly migration = {
|
|
54
|
+
name: "helper-presets",
|
|
55
|
+
up: async (sql: SQL) => {
|
|
56
|
+
await sql`
|
|
57
|
+
CREATE TABLE IF NOT EXISTS helper_presets (
|
|
58
|
+
guild_id text NOT NULL,
|
|
59
|
+
agent text NOT NULL,
|
|
60
|
+
name text NOT NULL,
|
|
61
|
+
display_name text NOT NULL,
|
|
62
|
+
prompt text NOT NULL,
|
|
63
|
+
skills jsonb NOT NULL DEFAULT '[]',
|
|
64
|
+
character jsonb,
|
|
65
|
+
model text,
|
|
66
|
+
thinking text,
|
|
67
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
68
|
+
PRIMARY KEY (guild_id, agent, name)
|
|
69
|
+
)`;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** The agent's presets, by name. */
|
|
74
|
+
async list(agent: string): Promise<HelperPreset[]> {
|
|
75
|
+
const rows: Row[] = await this.#sql`
|
|
76
|
+
SELECT * FROM helper_presets
|
|
77
|
+
WHERE guild_id = ${this.#guild} AND agent = ${agent} ORDER BY name`;
|
|
78
|
+
return rows.map(toPreset);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async get(agent: string, name: string): Promise<HelperPreset | undefined> {
|
|
82
|
+
const rows: Row[] = await this.#sql`
|
|
83
|
+
SELECT * FROM helper_presets
|
|
84
|
+
WHERE guild_id = ${this.#guild} AND agent = ${agent} AND name = ${name}`;
|
|
85
|
+
return rows[0] ? toPreset(rows[0]) : undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Saves the preset whole, refusing a new one past the cap; says whether it was new. */
|
|
89
|
+
async set(
|
|
90
|
+
agent: string,
|
|
91
|
+
preset: HelperPreset,
|
|
92
|
+
): Promise<"created" | "replaced"> {
|
|
93
|
+
const guild = this.#guild;
|
|
94
|
+
return this.#sql.begin(async (tx) => {
|
|
95
|
+
// One save per agent at a time, so two cannot both pass the cap.
|
|
96
|
+
await tx`SELECT pg_advisory_xact_lock(hashtext(${`helper-presets:${guild}:${agent}`}))`;
|
|
97
|
+
const [counted]: { others: number; same: number }[] = await tx`
|
|
98
|
+
SELECT count(*) FILTER (WHERE name <> ${preset.name})::int AS others,
|
|
99
|
+
count(*) FILTER (WHERE name = ${preset.name})::int AS same
|
|
100
|
+
FROM helper_presets WHERE guild_id = ${guild} AND agent = ${agent}`;
|
|
101
|
+
const replaced = (counted?.same ?? 0) > 0;
|
|
102
|
+
if (!replaced && (counted?.others ?? 0) >= MAX_HELPER_PRESETS)
|
|
103
|
+
throw new AgentError(
|
|
104
|
+
`You have ${MAX_HELPER_PRESETS} presets, the most you may keep; delete one with helper_preset_delete or replace one by saving under its name.`,
|
|
105
|
+
);
|
|
106
|
+
await tx`
|
|
107
|
+
INSERT INTO helper_presets
|
|
108
|
+
(guild_id, agent, name, display_name, prompt, skills, character, model, thinking)
|
|
109
|
+
VALUES (${guild}, ${agent}, ${preset.name}, ${preset.displayName}, ${preset.prompt},
|
|
110
|
+
${preset.skills}::jsonb, ${preset.character ?? null}::jsonb,
|
|
111
|
+
${preset.model ?? null}, ${preset.thinking ?? null})
|
|
112
|
+
ON CONFLICT (guild_id, agent, name) DO UPDATE SET
|
|
113
|
+
display_name = EXCLUDED.display_name, prompt = EXCLUDED.prompt,
|
|
114
|
+
skills = EXCLUDED.skills, character = EXCLUDED.character,
|
|
115
|
+
model = EXCLUDED.model, thinking = EXCLUDED.thinking, updated_at = now()`;
|
|
116
|
+
return replaced ? "replaced" : "created";
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Deletes one of the agent's presets; says whether there was one. */
|
|
121
|
+
async delete(agent: string, name: string): Promise<boolean> {
|
|
122
|
+
const rows = await this.#sql`
|
|
123
|
+
DELETE FROM helper_presets
|
|
124
|
+
WHERE guild_id = ${this.#guild} AND agent = ${agent} AND name = ${name}
|
|
125
|
+
RETURNING name`;
|
|
126
|
+
return rows.length > 0;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NO_ATTACHMENTS } from "../domain/attachment.ts";
|
|
2
2
|
import type { AgentTurnScope } from "../domain/ports.ts";
|
|
3
|
-
import type { Speaker } from "../speakers.ts";
|
|
3
|
+
import type { Speaker } from "../identity/speakers.ts";
|
|
4
4
|
import { OWNER_SPEAKER } from "../testing/owner.ts";
|
|
5
5
|
import { agentChannel, fx, settle } from "./agent-team-fixture.ts";
|
|
6
6
|
|
|
@@ -1,29 +1,54 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import type { AgentTurnScope } from "../domain/ports.ts";
|
|
3
|
-
import { THINKING_LEVELS } from "../models.ts";
|
|
4
3
|
import {
|
|
5
4
|
optionalString,
|
|
6
5
|
requiredString,
|
|
7
6
|
stringList,
|
|
8
7
|
type TextToolDef,
|
|
9
8
|
} from "../runtime/text-tools.ts";
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
9
|
+
import { MAX_PROMPT_CHARS } from "./agent-rules.ts";
|
|
10
|
+
import { CLASS, COLOR, lookOf } from "./agent-tool-schema.ts";
|
|
11
|
+
import type { AgentOps, HELPER_TOOLS } from "./agent-tools.ts";
|
|
12
|
+
import {
|
|
13
|
+
helperPresetToolDefs,
|
|
14
|
+
MODEL,
|
|
15
|
+
THINKING,
|
|
16
|
+
} from "./helper-preset-tools.ts";
|
|
12
17
|
|
|
13
18
|
/** The tools that make and end a knight's temp knights. */
|
|
14
19
|
export function helperToolDefs(
|
|
15
20
|
ops: AgentOps,
|
|
16
21
|
scope: AgentTurnScope,
|
|
17
22
|
skillsOn: boolean,
|
|
18
|
-
): TextToolDef<
|
|
23
|
+
): TextToolDef<(typeof HELPER_TOOLS)[number]>[] {
|
|
19
24
|
return [
|
|
20
25
|
{
|
|
21
26
|
name: "helper_create",
|
|
22
27
|
label: "Create temp knight",
|
|
23
|
-
description: `Make a temp knight (a helper knight) for one self-contained task that can run on its own, such as one of several things to look up or compare. It is a real agent with its own picture and place, listed under you; it starts at once and its answer comes back to you here as a new turn, like message_agent's. Make one per task, then end your turn; when the answers are in, merge them and clear the ones that are done with helper_end. It runs your model unless you give one, cannot make knights, temp knights or groups, and has no schedules. You may have a few at once, and when you are at the limit your oldest finished one is archived to make room.`,
|
|
28
|
+
description: `Make a temp knight (a helper knight) for one self-contained task that can run on its own, such as one of several things to look up or compare. It is a real agent with its own picture and place, listed under you; it starts at once and its answer comes back to you here as a new turn, like message_agent's. Make one per task, then end your turn; when the answers are in, merge them and clear the ones that are done with helper_end. It runs your model unless you give one, cannot make knights, temp knights or groups, and has no schedules. You may have a few at once, and when you are at the limit your oldest finished one is archived to make room. A temp knight you make often can be saved as a preset (helper_preset_set) and made by its name: what you give in the call replaces the preset's, and skills you give are added to the preset's.`,
|
|
24
29
|
parameters: Type.Object({
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
preset: Type.Optional(
|
|
31
|
+
Type.String({
|
|
32
|
+
description:
|
|
33
|
+
"A preset of yours, from helper_preset_list, that gives what you leave out here.",
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
display_name: Type.Optional(
|
|
37
|
+
Type.String({
|
|
38
|
+
minLength: 1,
|
|
39
|
+
maxLength: 32,
|
|
40
|
+
description:
|
|
41
|
+
"The name shown on its messages; any language. Required unless a preset gives it; given, it replaces the preset's.",
|
|
42
|
+
}),
|
|
43
|
+
),
|
|
44
|
+
prompt: Type.Optional(
|
|
45
|
+
Type.String({
|
|
46
|
+
minLength: 1,
|
|
47
|
+
maxLength: MAX_PROMPT_CHARS,
|
|
48
|
+
description:
|
|
49
|
+
"Its role prompt, in English: its job, sources, boundaries, and how it reports. Required unless a preset gives it; given, it replaces the preset's.",
|
|
50
|
+
}),
|
|
51
|
+
),
|
|
27
52
|
task: Type.String({
|
|
28
53
|
minLength: 1,
|
|
29
54
|
maxLength: 4000,
|
|
@@ -39,24 +64,14 @@ export function helperToolDefs(
|
|
|
39
64
|
),
|
|
40
65
|
class: Type.Optional(CLASS),
|
|
41
66
|
color: Type.Optional(COLOR),
|
|
42
|
-
model: Type.Optional(
|
|
43
|
-
|
|
44
|
-
description:
|
|
45
|
-
"The model to run on, as <provider>/<model>; left out, yours. An unusable one is refused with the usable list.",
|
|
46
|
-
}),
|
|
47
|
-
),
|
|
48
|
-
thinking: Type.Optional(
|
|
49
|
-
Type.Union(
|
|
50
|
-
[...THINKING_LEVELS, "default"].map((level) => Type.Literal(level)),
|
|
51
|
-
{ description: "Its thinking level; left out, yours." },
|
|
52
|
-
),
|
|
53
|
-
),
|
|
67
|
+
model: Type.Optional(MODEL),
|
|
68
|
+
thinking: Type.Optional(THINKING),
|
|
54
69
|
...(skillsOn
|
|
55
70
|
? {
|
|
56
71
|
skills: Type.Optional(
|
|
57
72
|
Type.Array(Type.String(), {
|
|
58
73
|
description:
|
|
59
|
-
"Skills it carries, from skill_list; pick those the task needs.",
|
|
74
|
+
"Skills it carries, from skill_list; pick those the task needs. With a preset, added to the preset's.",
|
|
60
75
|
}),
|
|
61
76
|
),
|
|
62
77
|
}
|
|
@@ -68,9 +83,13 @@ export function helperToolDefs(
|
|
|
68
83
|
const thinking = optionalString(i, "thinking");
|
|
69
84
|
const skills = stringList(i, "skills");
|
|
70
85
|
const look = lookOf(i);
|
|
86
|
+
const preset = optionalString(i, "preset");
|
|
87
|
+
const displayName = optionalString(i, "display_name");
|
|
88
|
+
const prompt = optionalString(i, "prompt");
|
|
71
89
|
return ops.helperCreate(scope, {
|
|
72
|
-
|
|
73
|
-
|
|
90
|
+
...(preset ? { preset } : {}),
|
|
91
|
+
...(displayName ? { displayName } : {}),
|
|
92
|
+
...(prompt ? { prompt } : {}),
|
|
74
93
|
task: requiredString(i, "task"),
|
|
75
94
|
...(name ? { name } : {}),
|
|
76
95
|
...(Object.keys(look).length > 0 ? { character: look } : {}),
|
|
@@ -100,5 +119,6 @@ export function helperToolDefs(
|
|
|
100
119
|
i.names === "finished" ? "finished" : (stringList(i, "names") ?? []),
|
|
101
120
|
),
|
|
102
121
|
},
|
|
122
|
+
...helperPresetToolDefs(ops, scope, skillsOn),
|
|
103
123
|
];
|
|
104
124
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { QueuePort } from "../contract/channels.ts";
|
|
2
2
|
import type { ChannelKey } from "../domain/conversation.ts";
|
|
3
|
-
import type { Logger } from "../log.ts";
|
|
3
|
+
import type { Logger } from "../kernel/log.ts";
|
|
4
4
|
import type { AgentTurnRunner } from "./agent-ports.ts";
|
|
5
5
|
import { isHelper } from "./agent-rules.ts";
|
|
6
6
|
import type { PgAgentStore } from "./agent-store.ts";
|