spurline-deploy 0.3.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.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/lib/spurline/adapters/base.rb +17 -0
  3. data/lib/spurline/adapters/claude.rb +208 -0
  4. data/lib/spurline/adapters/open_ai.rb +213 -0
  5. data/lib/spurline/adapters/registry.rb +33 -0
  6. data/lib/spurline/adapters/scheduler/base.rb +15 -0
  7. data/lib/spurline/adapters/scheduler/sync.rb +15 -0
  8. data/lib/spurline/adapters/stub_adapter.rb +54 -0
  9. data/lib/spurline/agent.rb +433 -0
  10. data/lib/spurline/audit/log.rb +156 -0
  11. data/lib/spurline/audit/secret_filter.rb +121 -0
  12. data/lib/spurline/base.rb +130 -0
  13. data/lib/spurline/cartographer/analyzer.rb +71 -0
  14. data/lib/spurline/cartographer/analyzers/ci_config.rb +171 -0
  15. data/lib/spurline/cartographer/analyzers/dotfiles.rb +134 -0
  16. data/lib/spurline/cartographer/analyzers/entry_points.rb +145 -0
  17. data/lib/spurline/cartographer/analyzers/file_signatures.rb +55 -0
  18. data/lib/spurline/cartographer/analyzers/manifests.rb +217 -0
  19. data/lib/spurline/cartographer/analyzers/security_scan.rb +223 -0
  20. data/lib/spurline/cartographer/repo_profile.rb +140 -0
  21. data/lib/spurline/cartographer/runner.rb +88 -0
  22. data/lib/spurline/cartographer.rb +6 -0
  23. data/lib/spurline/channels/base.rb +41 -0
  24. data/lib/spurline/channels/event.rb +136 -0
  25. data/lib/spurline/channels/github.rb +205 -0
  26. data/lib/spurline/channels/router.rb +103 -0
  27. data/lib/spurline/cli/check.rb +88 -0
  28. data/lib/spurline/cli/checks/adapter_resolution.rb +81 -0
  29. data/lib/spurline/cli/checks/agent_loadability.rb +41 -0
  30. data/lib/spurline/cli/checks/base.rb +35 -0
  31. data/lib/spurline/cli/checks/credentials.rb +43 -0
  32. data/lib/spurline/cli/checks/permissions.rb +22 -0
  33. data/lib/spurline/cli/checks/project_structure.rb +48 -0
  34. data/lib/spurline/cli/checks/session_store.rb +97 -0
  35. data/lib/spurline/cli/console.rb +73 -0
  36. data/lib/spurline/cli/credentials.rb +181 -0
  37. data/lib/spurline/cli/generators/agent.rb +123 -0
  38. data/lib/spurline/cli/generators/migration.rb +62 -0
  39. data/lib/spurline/cli/generators/project.rb +331 -0
  40. data/lib/spurline/cli/generators/tool.rb +98 -0
  41. data/lib/spurline/cli/router.rb +121 -0
  42. data/lib/spurline/configuration.rb +23 -0
  43. data/lib/spurline/dsl/guardrails.rb +108 -0
  44. data/lib/spurline/dsl/hooks.rb +51 -0
  45. data/lib/spurline/dsl/memory.rb +39 -0
  46. data/lib/spurline/dsl/model.rb +23 -0
  47. data/lib/spurline/dsl/persona.rb +74 -0
  48. data/lib/spurline/dsl/suspend_until.rb +53 -0
  49. data/lib/spurline/dsl/tools.rb +176 -0
  50. data/lib/spurline/errors.rb +109 -0
  51. data/lib/spurline/lifecycle/deterministic_runner.rb +207 -0
  52. data/lib/spurline/lifecycle/runner.rb +456 -0
  53. data/lib/spurline/lifecycle/states.rb +47 -0
  54. data/lib/spurline/lifecycle/suspension_boundary.rb +82 -0
  55. data/lib/spurline/memory/context_assembler.rb +100 -0
  56. data/lib/spurline/memory/embedder/base.rb +17 -0
  57. data/lib/spurline/memory/embedder/open_ai.rb +70 -0
  58. data/lib/spurline/memory/episode.rb +56 -0
  59. data/lib/spurline/memory/episodic_store.rb +147 -0
  60. data/lib/spurline/memory/long_term/base.rb +22 -0
  61. data/lib/spurline/memory/long_term/postgres.rb +106 -0
  62. data/lib/spurline/memory/manager.rb +147 -0
  63. data/lib/spurline/memory/short_term.rb +57 -0
  64. data/lib/spurline/orchestration/agent_spawner.rb +151 -0
  65. data/lib/spurline/orchestration/judge.rb +109 -0
  66. data/lib/spurline/orchestration/ledger/store/base.rb +28 -0
  67. data/lib/spurline/orchestration/ledger/store/memory.rb +50 -0
  68. data/lib/spurline/orchestration/ledger.rb +339 -0
  69. data/lib/spurline/orchestration/merge_queue.rb +133 -0
  70. data/lib/spurline/orchestration/permission_intersection.rb +151 -0
  71. data/lib/spurline/orchestration/task_envelope.rb +201 -0
  72. data/lib/spurline/persona/base.rb +42 -0
  73. data/lib/spurline/persona/registry.rb +42 -0
  74. data/lib/spurline/secrets/resolver.rb +65 -0
  75. data/lib/spurline/secrets/vault.rb +42 -0
  76. data/lib/spurline/security/content.rb +76 -0
  77. data/lib/spurline/security/context_pipeline.rb +58 -0
  78. data/lib/spurline/security/gates/base.rb +36 -0
  79. data/lib/spurline/security/gates/operator_config.rb +22 -0
  80. data/lib/spurline/security/gates/system_prompt.rb +23 -0
  81. data/lib/spurline/security/gates/tool_result.rb +23 -0
  82. data/lib/spurline/security/gates/user_input.rb +22 -0
  83. data/lib/spurline/security/injection_scanner.rb +109 -0
  84. data/lib/spurline/security/pii_filter.rb +104 -0
  85. data/lib/spurline/session/resumption.rb +36 -0
  86. data/lib/spurline/session/serializer.rb +169 -0
  87. data/lib/spurline/session/session.rb +154 -0
  88. data/lib/spurline/session/store/base.rb +27 -0
  89. data/lib/spurline/session/store/memory.rb +45 -0
  90. data/lib/spurline/session/store/postgres.rb +123 -0
  91. data/lib/spurline/session/store/sqlite.rb +139 -0
  92. data/lib/spurline/session/suspension.rb +93 -0
  93. data/lib/spurline/session/turn.rb +98 -0
  94. data/lib/spurline/spur.rb +213 -0
  95. data/lib/spurline/streaming/buffer.rb +77 -0
  96. data/lib/spurline/streaming/chunk.rb +62 -0
  97. data/lib/spurline/streaming/stream_enumerator.rb +29 -0
  98. data/lib/spurline/testing.rb +245 -0
  99. data/lib/spurline/toolkit.rb +110 -0
  100. data/lib/spurline/tools/base.rb +209 -0
  101. data/lib/spurline/tools/idempotency.rb +220 -0
  102. data/lib/spurline/tools/permissions.rb +44 -0
  103. data/lib/spurline/tools/registry.rb +43 -0
  104. data/lib/spurline/tools/runner.rb +255 -0
  105. data/lib/spurline/tools/scope.rb +309 -0
  106. data/lib/spurline/tools/toolkit_registry.rb +63 -0
  107. data/lib/spurline/version.rb +5 -0
  108. data/lib/spurline.rb +56 -0
  109. metadata +161 -0
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spurline
4
+ module DSL
5
+ # DSL for registering lifecycle event hooks.
6
+ # Registers configuration at class load time — never executes behavior.
7
+ module Hooks
8
+ HOOK_TYPES = %i[
9
+ on_start
10
+ on_turn_start
11
+ on_tool_call
12
+ on_turn_end
13
+ on_suspend
14
+ on_resume
15
+ on_finish
16
+ on_error
17
+ on_child_spawn
18
+ on_child_complete
19
+ on_child_error
20
+ ].freeze
21
+
22
+ def self.included(base)
23
+ base.extend(ClassMethods)
24
+ end
25
+
26
+ module ClassMethods
27
+ HOOK_TYPES.each do |hook_type|
28
+ define_method(hook_type) do |&block|
29
+ @hooks ||= {}
30
+ @hooks[hook_type] ||= []
31
+ @hooks[hook_type] << block
32
+ end
33
+ end
34
+
35
+ def hooks_config
36
+ own = @hooks || {}
37
+ if superclass.respond_to?(:hooks_config)
38
+ inherited = superclass.hooks_config
39
+ merged = inherited.dup
40
+ own.each do |type, blocks|
41
+ merged[type] = (merged[type] || []) + blocks
42
+ end
43
+ merged
44
+ else
45
+ own
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spurline
4
+ module DSL
5
+ # DSL for configuring agent memory stores.
6
+ # Registers configuration at class load time — never executes behavior.
7
+ module Memory
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def memory(type, **options)
14
+ @memory_config ||= {}
15
+ @memory_config[type.to_sym] = options
16
+ end
17
+
18
+ # Shorthand for toggling episodic memory recording.
19
+ #
20
+ # episodic false
21
+ # episodic true
22
+ #
23
+ def episodic(enabled = true)
24
+ @memory_config ||= {}
25
+ @memory_config[:episodic] = { enabled: !!enabled }
26
+ end
27
+
28
+ def memory_config
29
+ own = @memory_config || {}
30
+ if superclass.respond_to?(:memory_config)
31
+ superclass.memory_config.merge(own)
32
+ else
33
+ own
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spurline
4
+ module DSL
5
+ # DSL for configuring which LLM model an agent uses.
6
+ # Registers configuration at class load time — never executes behavior.
7
+ module Model
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def use_model(name, **options)
14
+ @model_config = { name: name.to_sym, **options }
15
+ end
16
+
17
+ def model_config
18
+ @model_config || (superclass.respond_to?(:model_config) ? superclass.model_config : nil)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spurline
4
+ module DSL
5
+ # DSL for defining agent personas (system prompts).
6
+ # Registers configuration at class load time — never executes behavior.
7
+ module Persona
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def persona(name = :default, &block)
14
+ @persona_configs ||= {}
15
+ config = PersonaConfig.new
16
+ config.instance_eval(&block)
17
+ @persona_configs[name.to_sym] = config
18
+ end
19
+
20
+ def persona_configs
21
+ own = @persona_configs || {}
22
+ inherited = if superclass.respond_to?(:persona_configs)
23
+ superclass.persona_configs
24
+ else
25
+ {}
26
+ end
27
+ inherited.merge(own)
28
+ end
29
+ end
30
+
31
+ # Internal config object for persona DSL blocks.
32
+ class PersonaConfig
33
+ attr_reader :system_prompt_text
34
+
35
+ def initialize
36
+ @system_prompt_text = ""
37
+ @_inject_date = false
38
+ @_inject_user_context = false
39
+ @_inject_agent_context = false
40
+ end
41
+
42
+ def system_prompt(text)
43
+ @system_prompt_text = text
44
+ end
45
+
46
+ # DSL setters (used inside persona blocks)
47
+ def inject_date(val = true)
48
+ @_inject_date = val
49
+ end
50
+
51
+ def inject_user_context(val = true)
52
+ @_inject_user_context = val
53
+ end
54
+
55
+ def inject_agent_context(val = true)
56
+ @_inject_agent_context = val
57
+ end
58
+
59
+ # Predicate readers (used when compiling persona config)
60
+ def date_injected?
61
+ @_inject_date
62
+ end
63
+
64
+ def user_context_injected?
65
+ @_inject_user_context
66
+ end
67
+
68
+ def agent_context_injected?
69
+ @_inject_agent_context
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../lifecycle/suspension_boundary"
4
+
5
+ module Spurline
6
+ module DSL
7
+ module SuspendUntil
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ # Declares a suspension condition for this agent class.
14
+ #
15
+ # Usage:
16
+ # suspend_until :tool_calls, count: 3
17
+ # suspend_until :custom, &block
18
+ def suspend_until(type = nil, **options, &block)
19
+ @suspension_config = { type: type, options: options, block: block }
20
+ end
21
+
22
+ def suspension_config
23
+ @suspension_config || superclass_suspension_config
24
+ end
25
+
26
+ # Builds a SuspensionCheck from the declarative config.
27
+ def build_suspension_check
28
+ config = suspension_config
29
+ return Lifecycle::SuspensionCheck.none unless config
30
+
31
+ case config[:type]
32
+ when :tool_calls
33
+ Lifecycle::SuspensionCheck.after_tool_calls(config[:options][:count])
34
+ when :custom
35
+ Lifecycle::SuspensionCheck.new(&config[:block])
36
+ else
37
+ Lifecycle::SuspensionCheck.none
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def superclass_suspension_config
44
+ if superclass.respond_to?(:suspension_config)
45
+ superclass.suspension_config
46
+ else
47
+ nil
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+ require "pathname"
3
+
4
+ module Spurline
5
+ module DSL
6
+ # DSL for declaring which tools an agent can use.
7
+ # Registers configuration at class load time — never executes behavior.
8
+ #
9
+ # Supports per-tool config overrides:
10
+ # tools :web_search, file_delete: { requires_confirmation: true, timeout: 30 }
11
+ module Tools
12
+ def self.included(base)
13
+ base.extend(ClassMethods)
14
+ end
15
+
16
+ module ClassMethods
17
+ IDEMPOTENCY_OPTION_KEYS = %i[
18
+ idempotent
19
+ idempotency_key
20
+ idempotency_ttl
21
+ idempotency_key_fn
22
+ ].freeze
23
+
24
+ def tools(*tool_names, **tool_configs)
25
+ @tool_config ||= { names: [], configs: {} }
26
+ tool_names.each { |name| @tool_config[:names] << name.to_sym }
27
+ tool_configs.each do |name, config|
28
+ @tool_config[:names] << name.to_sym
29
+ existing = @tool_config[:configs][name.to_sym]
30
+ @tool_config[:configs][name.to_sym] = existing ? existing.merge(config) : config
31
+ end
32
+ end
33
+
34
+ # Include one or more toolkits by name. Toolkit expansion is deferred
35
+ # until tool_config is accessed, so toolkits can be registered after
36
+ # agent classes are defined (supports any boot order).
37
+ #
38
+ # toolkits :git, :linear
39
+ # toolkits :provisioning, provisioning: { scoped: true }
40
+ #
41
+ def toolkits(*toolkit_names, **overrides)
42
+ @pending_toolkits ||= []
43
+ @pending_toolkits << { names: toolkit_names.map(&:to_sym), overrides: overrides }
44
+ end
45
+
46
+ def tool_config
47
+ expand_pending_toolkits!
48
+ own = @tool_config || { names: [], configs: {} }
49
+ if superclass.respond_to?(:tool_config)
50
+ inherited = superclass.tool_config
51
+ {
52
+ names: (inherited[:names] + own[:names]).uniq,
53
+ configs: inherited[:configs].merge(own[:configs]),
54
+ }
55
+ else
56
+ own
57
+ end
58
+ end
59
+
60
+ # Returns per-tool configuration for a specific tool.
61
+ def tool_config_for(tool_name)
62
+ tool_config[:configs][tool_name.to_sym] || {}
63
+ end
64
+
65
+ # Effective per-tool idempotency options from DSL config.
66
+ def idempotency_config
67
+ tool_config[:configs].each_with_object({}) do |(tool_name, config), result|
68
+ next unless config.is_a?(Hash)
69
+
70
+ options = symbolize_hash(config).slice(*IDEMPOTENCY_OPTION_KEYS)
71
+ next if options.empty?
72
+
73
+ result[tool_name.to_sym] = options
74
+ end
75
+ end
76
+
77
+ # Effective permissions applied by Tools::Runner.
78
+ # Merge order: spur defaults -> agent inline config -> YAML overrides.
79
+ def permissions_config
80
+ merged = {}
81
+ deep_merge_permissions!(merged, spur_default_permissions)
82
+ deep_merge_permissions!(merged, inline_tool_permissions)
83
+ deep_merge_permissions!(merged, yaml_permissions)
84
+ merged
85
+ end
86
+
87
+ private
88
+
89
+ def expand_pending_toolkits!
90
+ return unless instance_variable_defined?(:@pending_toolkits) && @pending_toolkits&.any?
91
+
92
+ pending = @pending_toolkits
93
+ @pending_toolkits = nil
94
+
95
+ pending.each do |ref|
96
+ ref[:names].each do |tk_name|
97
+ toolkit = self.toolkit_registry.fetch(tk_name)
98
+
99
+ # Toolkits own their tools — register them into the agent's tool registry.
100
+ toolkit.tool_classes.each do |tool_name, tool_class|
101
+ self.tool_registry.register(tool_name, tool_class) unless self.tool_registry.registered?(tool_name)
102
+ end
103
+
104
+ tool_names = toolkit.tools
105
+ shared = toolkit.shared_config
106
+
107
+ if shared.empty? && ref[:overrides].empty?
108
+ tools(*tool_names)
109
+ else
110
+ tool_configs = {}
111
+ tool_names.each do |tool_name|
112
+ merged = shared.dup
113
+ merged.merge!(ref[:overrides][tk_name] || {})
114
+ tool_configs[tool_name] = merged unless merged.empty?
115
+ end
116
+ tools(*tool_names, **tool_configs)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ def spur_default_permissions
123
+ return {} unless defined?(Spurline::Spur)
124
+
125
+ Spurline::Spur.registry.each_with_object({}) do |(_name, info), result|
126
+ next unless info.is_a?(Hash)
127
+
128
+ defaults = symbolize_hash(info[:permissions] || info["permissions"])
129
+ next if defaults.empty?
130
+
131
+ tools = info[:tools] || info["tools"] || []
132
+ tools.each do |tool_name|
133
+ result[tool_name.to_sym] ||= {}
134
+ result[tool_name.to_sym].merge!(defaults)
135
+ end
136
+ end
137
+ end
138
+
139
+ def inline_tool_permissions
140
+ tool_config[:configs].each_with_object({}) do |(tool_name, config), result|
141
+ result[tool_name.to_sym] = symbolize_hash(config)
142
+ end
143
+ end
144
+
145
+ def yaml_permissions
146
+ path = resolve_permissions_path
147
+ Spurline::Tools::Permissions.load_file(path)
148
+ end
149
+
150
+ def resolve_permissions_path
151
+ configured = Spurline.config.permissions_file
152
+ return nil if configured.nil? || configured.to_s.strip.empty?
153
+ return configured if Pathname.new(configured).absolute?
154
+
155
+ File.expand_path(configured.to_s, Dir.pwd)
156
+ end
157
+
158
+ def deep_merge_permissions!(base, incoming)
159
+ incoming.each do |tool_name, tool_config_hash|
160
+ key = tool_name.to_sym
161
+ base[key] ||= {}
162
+ base[key].merge!(symbolize_hash(tool_config_hash))
163
+ end
164
+ end
165
+
166
+ def symbolize_hash(value)
167
+ return {} unless value.is_a?(Hash)
168
+
169
+ value.each_with_object({}) do |(k, v), result|
170
+ result[k.to_sym] = v
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Eagerly loaded by lib/spurline.rb and ignored by Zeitwerk.
4
+ # This is the one file that breaks the autoloading convention, because
5
+ # error classes must be available before any framework code runs and
6
+ # they define multiple constants directly under Spurline.
7
+
8
+ module Spurline
9
+ # Base error for all Spurline errors. Rescue this to catch any framework error.
10
+ class AgentError < StandardError; end
11
+
12
+ # Raised when tainted content (trust: :external or :untrusted) is converted
13
+ # to a string via #to_s. Use Content#render instead, which applies data fencing.
14
+ class TaintedContentError < AgentError; end
15
+
16
+ # Raised when the injection scanner detects a prompt injection pattern
17
+ # in content flowing through the context pipeline.
18
+ class InjectionAttemptError < AgentError; end
19
+
20
+ # Raised when the PII filter in :block mode detects personally identifiable
21
+ # information in content. Switch to :redact mode to allow content through
22
+ # with PII replaced, or :off to disable filtering.
23
+ class PIIDetectedError < AgentError; end
24
+
25
+ # Raised when a tool execution is denied by the permission system.
26
+ # Check config/permissions.yml for the tool's permission requirements.
27
+ class PermissionDeniedError < AgentError; end
28
+
29
+ # Raised when code attempts to modify a compiled persona at runtime.
30
+ # Personas are frozen on class load — define a new persona instead.
31
+ class PersonaFrozenError < AgentError; end
32
+
33
+ # Raised when an agent attempts an invalid lifecycle state transition.
34
+ # Check Spurline::Lifecycle::States for valid transitions.
35
+ class InvalidStateError < AgentError; end
36
+
37
+ # Raised when a tool call references a tool name not in the registry.
38
+ # Ensure the tool's spur gem is installed and required.
39
+ class ToolNotFoundError < AgentError; end
40
+
41
+ # Raised when the per-turn tool call limit (guardrails.max_tool_calls) is exceeded.
42
+ # Increase the limit in the agent's guardrails block or restructure the task.
43
+ class MaxToolCallsError < AgentError; end
44
+
45
+ # Raised when a tool attempts to invoke another tool. Tools are leaf nodes (ADR-003).
46
+ # Use a Spurline::Skill if you need to compose multiple tools.
47
+ class NestedToolCallError < AgentError; end
48
+
49
+ # Raised when an adapter symbol cannot be resolved in the adapter registry.
50
+ # Ensure the adapter is registered before referencing it in use_model.
51
+ class AdapterNotFoundError < AgentError; end
52
+
53
+ # Raised when the sqlite3 gem is unavailable but the SQLite session store is used.
54
+ # Add gem "sqlite3" to the application bundle when configuring :sqlite session storage.
55
+ class SQLiteUnavailableError < AgentError; end
56
+
57
+ # Raised when the pg gem is unavailable but the Postgres session store is used.
58
+ # Add gem "pg" to the application bundle when configuring :postgres session storage.
59
+ class PostgresUnavailableError < AgentError; end
60
+
61
+ # Raised when persisted session payloads cannot be decoded into Session/Turn objects.
62
+ # This indicates corrupted or incompatible serialized session data.
63
+ class SessionDeserializationError < AgentError; end
64
+
65
+ # Raised when Spurline.configure or a DSL method receives invalid configuration.
66
+ # This always fires at class load time, never at runtime.
67
+ class ConfigurationError < AgentError; end
68
+
69
+ # Raised when encrypted credentials exist but no master key can be resolved.
70
+ class CredentialsMissingKeyError < AgentError; end
71
+
72
+ # Raised when encrypted credentials cannot be decrypted (bad key or tampered file).
73
+ class CredentialsDecryptionError < AgentError; end
74
+
75
+ # Raised when a required tool secret cannot be resolved from any configured source.
76
+ class SecretNotFoundError < AgentError; end
77
+
78
+ # Raised when an embedding provider or model fails to produce a valid vector.
79
+ class EmbedderError < AgentError; end
80
+
81
+ # Raised when long-term memory persistence or retrieval fails.
82
+ class LongTermMemoryError < AgentError; end
83
+
84
+ # Raised when a session cannot be suspended from its current state.
85
+ class SuspensionError < AgentError; end
86
+
87
+ # Raised when a resume is attempted for a non-suspended session.
88
+ class InvalidResumeError < AgentError; end
89
+
90
+ # Raised when Cartographer cannot access the target repository path.
91
+ class CartographerAccessError < AgentError; end
92
+
93
+ # Raised when an individual analyzer fails to produce valid output.
94
+ class AnalyzerError < AgentError; end
95
+ class ScopeViolationError < AgentError; end
96
+ class IdempotencyKeyConflictError < AgentError; end
97
+ class PrivilegeEscalationError < AgentError; end
98
+ class LedgerError < AgentError; end
99
+ class TaskEnvelopeError < AgentError; end
100
+ class MergeConflictError < AgentError; end
101
+
102
+ # Raised when a spawned child agent fails during execution.
103
+ # The message includes parent/child session IDs for audit correlation.
104
+ class SpawnError < AgentError; end
105
+
106
+ # Raised when a toolkit name cannot be resolved in the toolkit registry.
107
+ # Ensure the toolkit class is defined and loaded before referencing it.
108
+ class ToolkitNotFoundError < AgentError; end
109
+ end